Syntax10.Scn.Fnt Syntax10b.Scn.Fnt ParcElems Alloc Syntax10i.Scn.Fnt MODULE PSPrinter; (* JT 11.5.90, RC 2.7.93, JS 13.10.94, SHML 12 Jul 95, Amiga RD 30 Oct 95, PSFonts RD 3 Dec 95, PSFonts again hG 23 Jan 94, Pictures rewritten RD 24.3.96 *) IMPORT SYSTEM, PrinterDriver, Files, Texts, Oberon, Kernel, Amiga, Pictures, Display; CONST N = 20; maxFonts = 64; DefaultResolution = 300; defaultHeaderFileName = "Oberon.Header.ps"; CR = 0DX; LF = 0AX; NrPSFonts = 3; normal=0; bold=1; italic=2; magic=3; TYPE Name = ARRAY 32 OF CHAR; FontDesc = RECORD name: Name; used: ARRAY 8 OF SET END; RealVector = ARRAY N OF REAL; Poly = RECORD a, b, c, d, t: REAL END ; PolyVector = ARRAY N OF Poly; headerFileName, printFileName: Name; fontTable: ARRAY maxFonts OF FontDesc; fontIndex, curFont: INTEGER; listFont: Name; headerF, bodyF: Files.File; bodyR: Files.Rider; pno, ppos, plen: LONGINT; hexArray: ARRAY 17 OF CHAR; curR, curG, curB: INTEGER; resolution: INTEGER; FontsToMap: ARRAY NrPSFonts OF ARRAY 10 OF CHAR; (* PSFonts know to Oberon.Header.ps *) styleNames: ARRAY 4 OF ARRAY 10 OF CHAR; recodedPSFonts: ARRAY NrPSFonts OF SET; PROCEDURE IncPrintFile(VAR name:ARRAY OF CHAR); i:INTEGER; BEGIN i:=0; WHILE name[i]#0X DO INC(i) END; a i-5 a i-4 . i-3 p i-2 s i-1 i:=i-4; name[i]:=CHR(ORD(name[i])+1); IF (name[i]>"z") THEN name[i]:="a"; name[i-1]:=CHR(ORD(name[i-1])+1); IF (name[i-1]>"z") THEN name[i-1]:="a" END END END IncPrintFile; PROCEDURE Append(VAR s1: ARRAY OF CHAR; s2: ARRAY OF CHAR); VAR i, j: INTEGER; ch: CHAR; BEGIN i := 0; j := 0; WHILE s1[i] # 0X DO INC(i) END ; REPEAT ch := s2[j]; s1[i] := ch; INC(i); INC(j) UNTIL ch = 0X END Append; PROCEDURE ScanFirst(VAR s: Texts.Scanner); (* Scan first parameter *) VAR sel: Texts.Text; beg, end, time: LONGINT; BEGIN Texts.OpenScanner(s, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(s); IF (s.class = Texts.Char) & (s.line = 0) & (s.c = "^") THEN Oberon.GetSelection(sel, beg, end, time); IF time >= 0 THEN Texts.OpenScanner(s, sel, beg); Texts.Scan(s) ELSE s.class := Texts.Inval END END END ScanFirst; (* -- Output procedures -- *) PROCEDURE Ch (VAR R: Files.Rider; ch: CHAR); BEGIN Files.Write(R, ch) END Ch; PROCEDURE Str (VAR R: Files.Rider; s: ARRAY OF CHAR); VAR i: INTEGER; BEGIN i := 0; WHILE s[i] # 0X DO Ch(R, s[i]); INC(i) END END Str; PROCEDURE Int (VAR R: Files.Rider; i: LONGINT); VAR j: LONGINT; BEGIN IF i = 0 THEN Ch(R, "0") ELSIF i < 0 THEN i := -i; Ch(R, "-") END; j := 1; WHILE (i DIV j) # 0 DO j := j * 10 END; WHILE j >= 10 DO j := j DIV 10; Ch(R, CHR(ORD("0") + (i DIV j) MOD 10)) END END Int; PROCEDURE Hex(VAR R: Files.Rider; i: INTEGER); BEGIN IF i < 10 THEN Ch(R, CHR(i+ORD("0"))) ELSE Ch(R, CHR(i+(ORD("a")-10))) END END Hex; PROCEDURE Hex2(VAR R: Files.Rider; ch: CHAR); BEGIN Ch(R, hexArray[ORD(ch) DIV 16]); Ch(R, hexArray[ORD(ch) MOD 16]) END Hex2; PROCEDURE Ln(VAR R: Files.Rider); BEGIN Ch(R, 0AX) END Ln; (* -- Font Mapping -- *) PROCEDURE SetBitmapFont(VAR fontR, R: Files.Rider; fd: FontDesc; pRes: INTEGER); CONST fontFileId = 0DBX; TYPE RunRec = RECORD beg, end: INTEGER END; Metrics = RECORD dx, x, y, w, h: INTEGER END; VAR ch: CHAR; pixmapDX, n, b: LONGINT; k, m: INTEGER; height, minX, maxX, minY, maxY: INTEGER; nOfBoxes, nOfRuns: INTEGER; run: ARRAY 16 OF RunRec; metrics: ARRAY 256 OF Metrics; PROCEDURE Flip(ch: CHAR): CHAR; VAR i, s, d: INTEGER; BEGIN i := 0; s := ORD(ch); d := 0; WHILE i < 8 DO IF s MOD 2 = 1 THEN d := d * 2 + 1 ELSE d := d * 2 END; s := s DIV 2; INC(i) END; RETURN CHR(d) END Flip; PROCEDURE Name(m: INTEGER); BEGIN CASE m OF | 9: Str(fontR, "tab") | 32: Str(fontR, "space") | 33: Str(fontR, "exclam") | 34: Str(fontR, "quotedbl") | 35: Str(fontR, "numbersign") | 36: Str(fontR, "dollar") | 37: Str(fontR, "percent") | 38: Str(fontR, "ampersand") | 39: Str(fontR, "quotesingle") | 40: Str(fontR, "parenleft") | 41: Str(fontR, "parenright") | 42: Str(fontR, "asterisk") | 43: Str(fontR, "plus") | 44: Str(fontR, "comma") | 45: Str(fontR, "minus") | 46: Str(fontR, "period") | 47: Str(fontR, "slash") | 48: Str(fontR, "zero") | 49: Str(fontR, "one") | 50: Str(fontR, "two") | 51: Str(fontR, "three") | 52: Str(fontR, "four") | 53: Str(fontR, "five") | 54: Str(fontR, "six") | 55: Str(fontR, "seven") | 56: Str(fontR, "eight") | 57: Str(fontR, "nine") | 58: Str(fontR, "colon") | 59: Str(fontR, "semicolon") | 60: Str(fontR, "less") | 61: Str(fontR, "equal") | 62: Str(fontR, "greater") | 63: Str(fontR, "question") | 64: Str(fontR, "at") | 65..90: Ch(fontR, CHR(m)) | 91: Str(fontR, "bracketleft") | 92: Str(fontR, "backslash") | 93: Str(fontR, "bracketright") | 94: Str(fontR, "arrowup") | 95: Str(fontR, "underscore") | 96: Str(fontR, "grave") | 97..122: Ch(fontR, CHR(m)) | 123: Str(fontR, "braceleft") | 124: Str(fontR, "bar") | 125: Str(fontR, "braceright") | 126: Str(fontR, "tilde") | 128: Str(fontR, "Adieresis") | 129: Str(fontR, "Odieresis") | 130: Str(fontR, "Udieresis") | 131: Str(fontR, "adieresis") | 132: Str(fontR, "odieresis") | 133: Str(fontR, "udieresis") | 134: Str(fontR, "acircumflex") | 135: Str(fontR, "ecircumflex") | 136: Str(fontR, "icircumflex") | 137: Str(fontR, "oicircumflex") | 138: Str(fontR, "uicircumflex") | 139: Str(fontR, "agrave") | 140: Str(fontR, "egrave") | 141: Str(fontR, "igrave") | 142: Str(fontR, "ograve") | 143: Str(fontR, "ugrave") | 144: Str(fontR, "eacute") | 145: Str(fontR, "edieresis") | 146: Str(fontR, "idieresis") | 147: Str(fontR, "ccedilla") | 148: Str(fontR, "aacute") | 149: Str(fontR, "ntilde") | 155: Str(fontR, "endash") | 159: Str(fontR, "hyphen") | 171: Str(fontR, "germandbls") ELSE Str(fontR, "ascii"); Ch(fontR, CHR(ORD("0") + (m DIV 100) MOD 10)); Ch(fontR, CHR(ORD("0") + (m DIV 10) MOD 10)); Ch(fontR, CHR(ORD("0") + m MOD 10)) END END Name; BEGIN Str(fontR, "% Conversion of the Oberon font "); Str(fontR, fd.name); Ln(fontR); Files.Read(R, ch); IF ch = fontFileId THEN Files.Read(R, ch); Str(fontR, "% abstraction: "); Int(fontR, ORD(ch)); Files.Read(R, ch); Str(fontR, ", family: "); Ch(fontR, ch); Files.Read(R, ch); Str(fontR, ", variant: "); Int(fontR, ORD(ch)); Ln(fontR); Files.ReadInt(R, height); Str(fontR, "% height: "); Int(fontR, height); Ln(fontR); Ln(fontR); Files.ReadInt(R, minX); Files.ReadInt(R, maxX); Files.ReadInt(R, minY); Files.ReadInt(R, maxY); Files.ReadInt(R, nOfRuns); nOfBoxes := 0; k := 0; WHILE k # nOfRuns DO Files.ReadInt(R, run[k].beg); Files.ReadInt(R, run[k].end); INC(nOfBoxes, run[k].end - run[k].beg); INC(k) END; Str(fontR, "9 dict begin"); Ln(fontR); Ln(fontR); Str(fontR, "/FontType 3 def"); Ln(fontR); Str(fontR, "/FontMatrix [ 72 "); Int(fontR, pRes); Str(fontR, " div "); Str(fontR, " .24 div 0 0 "); Str(fontR, "72 "); Int(fontR, pRes); Str(fontR, " div "); Str(fontR, " .24 div 0 0"); Str(fontR, "] def"); Ln(fontR); Str(fontR, "/FontBBox ["); Int(fontR, minX); Ch(fontR, " "); Int(fontR, minY); Ch(fontR, " "); Int(fontR, maxX); Ch(fontR, " "); Int(fontR, maxY); Str(fontR, "] def"); Ln(fontR); (* hG/23-Jan-1996 Str(fontR, "/Encoding 256 array def"); Ln(fontR); Str(fontR, "0 1 255 {Encoding exch /.notdef put} for"); Ln(fontR); Str(fontR, "Encoding OberonEncoding OberonXEncoding OberonYEncoding /Encoding exch def"); Ln(fontR); Ln(fontR); Str(fontR, "/Encoding FullOberonEncoding def"); Ln(fontR); Ln(fontR); (* hG/23-Jan-1996 *) Str(fontR, "/CharData "); Int(fontR, nOfBoxes+1); Str(fontR, " dict def"); Ln(fontR); Str(fontR, "CharData begin"); Ln(fontR); k := 0; m := 0; WHILE k < nOfRuns DO m := run[k].beg; WHILE m < run[k].end DO Files.ReadInt(R, metrics[m].dx); Files.ReadInt(R, metrics[m].x); Files.ReadInt(R, metrics[m].y); Files.ReadInt(R, metrics[m].w); Files.ReadInt(R, metrics[m].h); INC(m) END; INC(k) END; Str(fontR, "/.notdef"); Str(fontR, " ["); Int(fontR, metrics[32].w); Str(fontR, " 0 0 0 0 1 1 0 0"); Ln(fontR); Str(fontR, "<>] bdef"); Ln(fontR); k := 0; m := 0; WHILE k < nOfRuns DO m := run[k].beg; WHILE m < run[k].end DO IF m MOD 32 IN fd.used[m DIV 32] THEN Str(fontR, "/"); Name(m); Str(fontR, " ["); Int(fontR, metrics[m].dx); Str(fontR, " "); Int(fontR, metrics[m].x); Str(fontR, " "); Int(fontR, metrics[m].y); Str(fontR, " "); Int(fontR, metrics[m].x + metrics[m].w); Str(fontR, " "); Int(fontR, metrics[m].y + metrics[m].h); Str(fontR, " "); IF metrics[m].w > 0 THEN Int(fontR, metrics[m].w) ELSE Int(fontR, 1) END; Str(fontR, " "); IF metrics[m].h > 0 THEN Int(fontR, metrics[m].h) ELSE Int(fontR, 1) END; Str(fontR, " "); Int(fontR, -metrics[m].x); Str(fontR, " "); Int(fontR, -metrics[m].y); Ln(fontR); Str(fontR, "<"); pixmapDX := (metrics[m].w + 7) DIV 8; n := pixmapDX * metrics[m].h; b := 0; WHILE b < n DO Files.Read(R, ch); Hex2(fontR, Flip(ch)); INC(b); IF b MOD 32 = 0 THEN Ln(fontR); Str(fontR, " ") END END; Str(fontR, ">] bdef"); Ln(fontR) ELSE n := (metrics[m].w + 7) DIV 8 * metrics[m].h; b := 0; WHILE b < n DO Files.Read(R, ch); INC(b) END END; INC(m) END; INC(k) END; Str(fontR, " end"); Ln(fontR); Ln(fontR); Str(fontR, "/BuildGlyph {GlobalBuildGlyph} bdef"); Ln(fontR); Str(fontR, "/BuildChar {GlobalBuildChar} bdef"); Ln(fontR); Ln(fontR); Str(fontR, "/imageMaskMatrix [1 0 0 1 0 0] bdef"); Ln(fontR); Ln(fontR); Str(fontR, "currentdict"); Ln(fontR); Ln(fontR); Str(fontR, "end"); Ln(fontR); Ln(fontR); Ch(fontR, "/"); Str(fontR, fd.name); Ch(fontR, "D"); Str(fontR, " exch definefont pop"); Ln(fontR); Ch(fontR, "/"); Str(fontR, fd.name); Str(fontR, " {/"); Str(fontR, fd.name); Str(fontR, "D f} bdef"); Ln(fontR); Ln(fontR) END END SetBitmapFont; PROCEDURE SetPSFont(VAR R: Files.Rider; n: ARRAY OF CHAR): BOOLEAN; VAR PSFont, Pos, Typ, w: INTEGER; (* Search for Font in Mapping List *) PROCEDURE TestPSFont(VAR Name: ARRAY OF CHAR; VAR PSFont, Pos: INTEGER); VAR i, j: INTEGER; BEGIN FOR i:=0 TO NrPSFonts-1 DO j:=-1; REPEAT INC(j); IF FontsToMap[i,j]=CHR(0) THEN Pos:=j; PSFont:=i; RETURN END UNTIL Name[j]#FontsToMap[i,j] END; Pos:=-1 END TestPSFont; BEGIN TestPSFont(n, PSFont, Pos); IF Pos<0 THEN RETURN FALSE END; (* entry in mapping list ? no => FALSE *) w:=0; WHILE (ORD(n[Pos])<58) & (ORD(n[Pos])>=48) DO w:=w*10+ORD(n[Pos])-48; INC(Pos) END; CASE n[Pos] OF | ".": Typ:= normal | "b": Typ:= bold | "i": Typ:= italic | "m": Typ:= magic ELSE Typ:= normal END; IF ~ (Typ IN recodedPSFonts[PSFont]) THEN INCL(recodedPSFonts[PSFont], Typ); Str(R, "/Ob-"); Str(R, FontsToMap[PSFont]); Str (R, styleNames[Typ]); Str(R, " "); Str(R, FontsToMap[PSFont]); Str(R, styleNames[Typ]); Str(R, ".Fnt recode"); Ln(R); END; Ch(R, "/"); Str(R, n); Str(R, " {/Ob-"); Str(R, FontsToMap[PSFont]); Str (R, styleNames[Typ]); Str(R, " "); Int(R, w); Str(R, " "); Str(R, FontsToMap[PSFont]); Str(R, "-ScaleFactor MF} bdef"); Ln(R); Ln(R); RETURN TRUE END SetPSFont; PROCEDURE DefineFont(VAR fontR: Files.Rider; fd: FontDesc); VAR name: ARRAY 32 OF CHAR; i, size: INTEGER; VAR f: Files.File; R: Files.Rider; BEGIN COPY(fd.name, name); i := 0; size := 0; WHILE (name[i] # 0X) & (name[i] # ".") & ((name[i] < "0") OR (name[i] > "9")) DO INC(i) END; WHILE (name[i] >= "0") & (name[i] <= "9") DO size := size * 10 + ORD(name[i]) - ORD("0"); INC(i) END; WHILE (name[i] # 0X) & (name[i] # ".") DO INC(i) END; IF (name[i] # ".") OR (name[i+1] # "S") OR (name[i+2] #"c") OR (name[i+3] # "n") THEN PrinterDriver.Error(name, " illegal font name") ELSE name[i+1] := "P"; name[i+2] := "r"; name[i+3] := "3"; f := Files.Old(name); IF f = NIL THEN IF ~SetPSFont(fontR, fd.name) THEN PrinterDriver.Error(name, " font missing and can not find PS font") END ELSE Files.Set(R, f, 0); SetBitmapFont(fontR, R, fd, resolution) END END END DefineFont; (* -- Printing Procedures -- *) PROCEDURE Open(VAR name, user: ARRAY OF CHAR; password: LONGINT); BEGIN curR := 0; curG := 0; curB := 0; PrinterDriver.res := 0; PrinterDriver.err := FALSE; resolution := DefaultResolution; (* COPY(name, printFileName); *) i := -1; REPEAT INC(i); printFileName[i] := name[i] UNTIL printFileName[i] = 0X; resolution := 0; mul := 1; LOOP DEC(i); ch := name[i]; IF (i = 0) OR (ch = ".") THEN printFileName[i] := 0X; EXIT END; IF ("0" <= ch) & (ch <= "9") THEN INC(resolution, mul*(ORD(ch)-ORD("0"))); mul := 10*mul ELSE printFileName[i+1] := 0X; resolution := DefaultResolution; EXIT END END; headerF := Files.Old(headerFileName); IF headerF # NIL THEN bodyF := Files.New(""); Files.Set(bodyR, bodyF, 0); recodedPSFonts[0] := {}; recodedPSFonts[1] := {}; recodedPSFonts[2] := {}; fontIndex := -1; curFont := -1; listFont := ""; ppos := 0; pno := 1 ELSE PrinterDriver.Error("file not found", headerFileName) END END Open; PROCEDURE UseListFont(VAR name: ARRAY OF CHAR); BEGIN COPY(name, listFont); curFont := -1 END UseListFont; PROCEDURE ReplConst(x, y, w, h: INTEGER); BEGIN IF (w > 0) & (h > 0) THEN Int(bodyR, x+1); Ch(bodyR, " "); Int(bodyR, y); Ch(bodyR, " "); Int(bodyR, w-1); Ch(bodyR, " "); Int(bodyR, h-1); Str(bodyR, " l"); Ln(bodyR) END END ReplConst; PROCEDURE ContString(VAR s, fname: ARRAY OF CHAR); VAR fNo, i, n: INTEGER; ch: CHAR; family: ARRAY 7 OF CHAR; fontName: ARRAY 32 OF CHAR; PROCEDURE Use(ch: CHAR); BEGIN INCL(fontTable[curFont].used[ORD(ch) DIV 32], ORD(ch) MOD 32) END Use; BEGIN IF fname = listFont THEN fontName := "Courier8.Scn.Fnt" ELSE COPY (fname, fontName) END; IF (curFont < 0) OR (fontTable[curFont].name # fontName) THEN COPY(fontName, fontTable[fontIndex+1].name); i := 0; WHILE i < 8 DO fontTable[fontIndex+1].used[i] := {}; INC(i) END; fNo := 0; WHILE fontTable[fNo].name # fontName DO INC(fNo) END; IF fNo > fontIndex THEN (* DefineFont(fontName); *) fontIndex := fNo END; curFont := fNo; Str(bodyR, fontTable[curFont].name); Ch(bodyR, " ") (* something killed here *) END; Ch(bodyR, "("); i := 0; ch := s[0]; WHILE ch # 0X DO CASE ch OF | "(", ")", "\": Ch(bodyR, "\"); Ch(bodyR, ch); Use(ch) | 9X: Str(bodyR, " "); Use(" ") (* or Str("\tab") *) | 80X..95X, 0ABX: Str(bodyR, "\2"); n := ORD(ch)-128; Ch(bodyR, CHR(n DIV 8 + 48)); Ch(bodyR, CHR(n MOD 8 + 48)); Use(ch) | 9FX: COPY(fontTable[curFont].name, family); IF family = "Courie" THEN Ch(bodyR, " ") ELSE Str(bodyR, " ") END; Use(" ") ELSE IF (ORD(ch) >= 32) & (ORD(ch) < 127) THEN Ch(bodyR, ch) ELSE Ch(bodyR, "\"); Ch(bodyR, CHR((ORD(ch) DIV 64) MOD 8 + ORD("0"))); Ch(bodyR, CHR((ORD(ch) DIV 8) MOD 8 + ORD("0"))); Ch(bodyR, CHR(ORD(ch) MOD 8 + ORD("0"))) END; Use(ch) END ; INC(i); ch := s[i] END; Str(bodyR, ") s"); Ln(bodyR) END ContString; PROCEDURE String(x, y: INTEGER; VAR s, fname: ARRAY OF CHAR); BEGIN Int(bodyR, x); Ch(bodyR, " "); Int(bodyR, y); Str(bodyR, " m "); ContString(s, fname) END String; PROCEDURE ReplPattern(x, y, w, h, col: INTEGER); BEGIN Int(bodyR, x+1); Ch(bodyR, " "); Int(bodyR, y); Ch(bodyR, " "); Int(bodyR, w-1); Ch(bodyR, " "); Int(bodyR, h-1); Ch(bodyR, " "); Int(bodyR, col); Str(bodyR, " b"); Ln(bodyR) END ReplPattern; (* rewritten by RD 24.3.1996 *) PROCEDURE Picture(x, y, w, h, mode: INTEGER; adr: LONGINT); VAR n, i, z1, z2, v: INTEGER; ch: CHAR; P: Pictures.Picture; Map: ARRAY 256 OF BOOLEAN; PROCEDURE InitMap; VAR r, g, b, i: INTEGER; BEGIN FOR i:=0 TO 255 DO Display.GetColor(i, r, g, b); Map[i]:=((r+g+b)DIV 3)>Amiga.PictPrintThresh END; END InitMap; (*PROCEDURE Flip(ch: CHAR): CHAR; VAR i, s, d: INTEGER; BEGIN i := 0; s := ORD(ch); d := 0; WHILE i < 8 DO IF s MOD 2 = 1 THEN d := d * 2 + 1 ELSE d := d * 2 END; s := s DIV 2; INC(i) END; RETURN CHR(d) END Flip;*) BEGIN InitMap; Int(bodyR, x); Ch(bodyR, " "); Int(bodyR, y); Ch(bodyR, " "); Int(bodyR, w); Ch(bodyR, " "); Int(bodyR, h); Ch(bodyR, " "); Int(bodyR,mode); Str(bodyR, " i"); i:=0; n:=(w+7) DIV 8; adr:=adr+n*h; FOR z1:=0 TO h-1 DO adr:=adr-n; FOR z2:=0 TO n-1 DO SYSTEM.GET(adr+z2, ch); (* ch := Flip(ch); *) IF i MOD 40 = 0 THEN Ln(bodyR) END ; v := (-ORD(ch)-1) MOD 256; Hex(bodyR, v DIV 16); Hex(bodyR, v MOD 16); INC(i) END END ; w:=((w+7) DIV 8)*8; Ln(bodyR); P:=Pictures.ToPrint; FOR z2:=0 TO h-1 DO FOR z1:=0 TO w-1 BY 4 DO v:=0; IF Map[Pictures.Get(P, z1, z2)] THEN INC(v,8) END; IF Map[Pictures.Get(P, z1+1, z2)] THEN INC(v,4) END; IF Map[Pictures.Get(P, z1+2, z2)] THEN INC(v,2) END; IF Map[Pictures.Get(P, z1+4, z2)] THEN INC(v,1) END; Hex(bodyR, v); INC(i); IF i = 80 THEN i:=0; Ln(bodyR) END; END; END; Ln(bodyR) END Picture; PROCEDURE Circle(x0, y0, r: INTEGER); BEGIN Int(bodyR, x0); Ch(bodyR, " "); Int(bodyR, y0); Ch(bodyR, " "); Int(bodyR, r); Ch(bodyR, " "); Int(bodyR, r); Str(bodyR, " c"); Ln(bodyR) END Circle; PROCEDURE Ellipse(x0, y0, a, b: INTEGER); BEGIN Int(bodyR, x0); Ch(bodyR, " "); Int(bodyR, y0); Ch(bodyR, " "); Int(bodyR, a); Ch(bodyR, " "); Int(bodyR, b); Str(bodyR, " c"); Ln(bodyR) END Ellipse; PROCEDURE Line(x0, y0, x1, y1: INTEGER); BEGIN Int(bodyR, x0); Ch(bodyR, " "); Int(bodyR, y0); Ch(bodyR, " "); Int(bodyR, x1-x0); Ch(bodyR, " "); Int(bodyR, y1-y0); Str(bodyR, " x"); Ln(bodyR) END Line; PROCEDURE UseColor(red, green, blue: INTEGER); BEGIN IF (red # curR) OR (green # curG) OR (blue # curB) THEN curR := red; curG := green; curB := blue; Int(bodyR, curR); Str(bodyR, " 255 div "); Int(bodyR, curG); Str(bodyR, " 255 div "); Int(bodyR, curB); Str(bodyR, " 255 div u"); Ln(bodyR) END END UseColor; (* -- Spline computation -- *) PROCEDURE SolveTriDiag(VAR a, b, c, y: RealVector; n: INTEGER); VAR i: INTEGER; BEGIN (*a, b, c of tri-diag matrix T; solve Ty' = y for y', assign y' to y*) i := 1; WHILE i < n DO y[i] := y[i] - c[i-1]*y[i-1]; INC(i) END ; i := n-1; y[i] := y[i]/a[i]; WHILE i > 0 DO DEC(i); y[i] := (y[i] - b[i]*y[i+1])/a[i] END END SolveTriDiag; PROCEDURE OpenSpline(VAR x, y, d: RealVector; n: INTEGER); VAR i: INTEGER; d1, d2: REAL; a, b, c: RealVector; BEGIN (*from x, y compute d = y'*) b[0] := 1.0/(x[1] - x[0]); a[0] := 2.0*b[0]; c[0] := b[0]; d1 := (y[1] - y[0])*3.0*b[0]*b[0]; d[0] := d1; i := 1; WHILE i < n-1 DO b[i] := 1.0/(x[i+1] - x[i]); a[i] := 2.0*(c[i-1] + b[i]); c[i] := b[i]; d2 := (y[i+1] - y[i])*3.0*b[i]*b[i]; d[i] := d1 + d2; d1 := d2; INC(i) END ; a[i] := 2.0*b[i-1]; d[i] := d1; i := 0; WHILE i < n-1 DO c[i] := c[i]/a[i]; a[i+1] := a[i+1] - c[i]*b[i]; INC(i) END ; SolveTriDiag(a, b, c, d, n) END OpenSpline; PROCEDURE ClosedSpline(VAR x, y, d: RealVector; n: INTEGER); VAR i: INTEGER; d1, d2, hn, dn: REAL; a, b, c, w: RealVector; BEGIN (*from x, y compute d = y'*) hn := 1.0/(x[n-1] - x[n-2]); dn := (y[n-1] - y[n-2])*3.0*hn*hn; b[0] := 1.0/(x[1] - x[0]); a[0] := 2.0*b[0] + hn; c[0] := b[0]; d1 := (y[1] - y[0])*3.0*b[0]*b[0]; d[0] := dn + d1; w[0] := 1.0; i := 1; WHILE i < n-2 DO b[i] := 1.0/(x[i+1] - x[i]); a[i] := 2.0*(c[i-1] + b[i]); c[i] := b[i]; d2 := (y[i+1] - y[i])*3.0*b[i]*b[i]; d[i] := d1 + d2; d1 := d2; w[i] := 0; INC(i) END ; a[i] := 2.0*b[i-1] + hn; d[i] := d1 + dn; w[i] := 1.0; i := 0; WHILE i < n-2 DO c[i] := c[i]/a[i]; a[i+1] := a[i+1] - c[i]*b[i]; INC(i) END ; SolveTriDiag(a, b, c, d, n-1); SolveTriDiag(a, b, c, w, n-1); d1 := (d[0] + d[i])/(w[0] + w[i] + x[i+1] - x[i]); i := 0; WHILE i < n-1 DO d[i] := d[i] - d1*w[i]; INC(i) END ; d[i] := d[0] END ClosedSpline; PROCEDURE PrintPoly(VAR p, q: Poly; lim: REAL); VAR x0, y0, x1, y1, x2, y2, x3, y3: REAL; BEGIN x0 := p.d; y0 := q.d; x1 := x0 + p.c*lim/3.0; y1 := y0 + q.c*lim/3.0; x2 := x1 + (p.c + p.b*lim)*lim/3.0; y2 := y1 + (q.c + q.b*lim)*lim/3.0; x3 := x0 + (p.c + (p.b + p.a*lim)*lim)*lim; y3 := y0 + (q.c + (q.b + q.a*lim)*lim)*lim; Int(bodyR, ENTIER(x1)); Ch(bodyR, " "); Int(bodyR, ENTIER(y1)); Ch(bodyR, " "); Int(bodyR, ENTIER(x2)); Ch(bodyR, " "); Int(bodyR, ENTIER(y2)); Ch(bodyR, " "); Int(bodyR, ENTIER(x3)); Ch(bodyR, " "); Int(bodyR, ENTIER(y3)); Ch(bodyR, " "); Int(bodyR, ENTIER(x0)); Ch(bodyR, " "); Int(bodyR, ENTIER(y0)); Str(bodyR, " z"); Ln(bodyR) END PrintPoly; PROCEDURE Spline(x0, y0, n, open: INTEGER; VAR X, Y: ARRAY OF INTEGER); VAR i: INTEGER; dx, dy, ds: REAL; x, xd, y, yd, s: RealVector; p, q: PolyVector; BEGIN (*from u, v compute x, y, s*) x[0] := X[0] + x0; y[0] := Y[0] + y0; s[0] := 0; i := 1; WHILE i < n DO x[i] := X[i] + x0; dx := x[i] - x[i-1]; y[i] := Y[i] + y0; dy := y[i] - y[i-1]; s[i] := ABS(dx) + ABS(dy) + s[i-1]; INC(i) END ; IF open = 1 THEN OpenSpline(s, x, xd, n); OpenSpline(s, y, yd, n) ELSE ClosedSpline(s, x, xd, n); ClosedSpline(s, y, yd, n) END ; (*compute coefficients from x, y, xd, yd, s*) i := 0; WHILE i < n-1 DO ds := 1.0/(s[i+1] - s[i]); dx := (x[i+1] - x[i])*ds; p[i].a := ds*ds*(xd[i] + xd[i+1] - 2.0*dx); p[i].b := ds*(3.0*dx - 2.0*xd[i] -xd[i+1]); p[i].c := xd[i]; p[i].d := x[i]; p[i].t := s[i]; dy := ds*(y[i+1] - y[i]); q[i].a := ds*ds*(yd[i] + yd[i+1] - 2.0*dy); q[i].b := ds*(3.0*dy - 2.0*yd[i] - yd[i+1]); q[i].c := yd[i]; q[i].d := y[i]; q[i].t := s[i]; INC(i) END ; p[i].t := s[i]; q[i].t := s[i]; (*print polynomials*) i := 0; WHILE i < n-1 DO PrintPoly(p[i], q[i], p[i+1].t - p[i].t); INC(i) END END Spline; PROCEDURE Page(nofcopies: INTEGER); BEGIN curR := 0; curG := 0; curB := 0; Int(bodyR, nofcopies); Str(bodyR, " p"); Ln(bodyR); curFont := -1; INC(pno); ppos := Files.Pos(bodyR); Str(bodyR, "%%Page: 0 "); Int(bodyR, pno); plen := Files.Pos(bodyR) - ppos; Ln(bodyR) END Page; PROCEDURE Close; CONST bufSize = 4*1024; VAR i: INTEGER; printF: Files.File; printR, srcR: Files.Rider; buffer: ARRAY bufSize OF SYSTEM.BYTE; cmd: ARRAY 512 OF CHAR; BEGIN IF ~PrinterDriver.err THEN Str(bodyR, "OberonClose"); Ln(bodyR); Files.Set(bodyR, bodyF, ppos); (*overwrite last %%Page line*) Str(bodyR, "%%Trailer"); DEC(plen, 9); WHILE plen > 0 DO Ch(bodyR, " "); DEC(plen) END; cmd:="t:"; Append(cmd, printFileName); printF := Files.New(cmd); Files.Set(printR, printF, 0); Str(printR, "%!PS-Adobe- minimal conforming"); Ln(printR); Str(printR, "%%Creator: Oberon System V4 for Amiga"); Ln(printR); Str(printR, "%"); Ln(printR); Str(printR, "% Institute for Computer Systems, ETH Zurich, 1990-1995"); Ln(printR); Str(printR, "%"); Ln(printR); Files.Set(srcR, headerF, 0); Files.ReadBytes(srcR, buffer, bufSize); WHILE ~srcR.eof DO Files.WriteBytes(printR, buffer, bufSize); Files.ReadBytes(srcR, buffer, bufSize) END; IF srcR.res # bufSize THEN Files.WriteBytes(printR, buffer, bufSize-srcR.res) END; i := 0; WHILE i <= fontIndex DO DefineFont(printR, fontTable[i]); INC(i) END; Str(printR, "OberonInit"); Ln(printR); Str(printR, "save"); Ln(printR); Str(printR, "%%EndProlog"); Ln(printR); Ln(printR); Str(printR, "%%Page: 0 1"); Ln(printR); Files.Set(srcR, bodyF, 0); Files.ReadBytes(srcR, buffer, bufSize); WHILE ~srcR.eof DO Files.WriteBytes(printR, buffer, bufSize); Files.ReadBytes(srcR, buffer, bufSize) END; IF srcR.res # bufSize THEN Files.WriteBytes(printR, buffer, bufSize-srcR.res) END; Files.Register(printF); (* Files.Set(bodyR, NIL, 0); *) headerF := NIL; bodyF := NIL; printF := NIL; Kernel.GC(TRUE); (* Release the file immediately *) (* NOTE: In contrary to the Unix implementation, this one does not itself treat none as special file name, nor does it delete the file. Its up to the command/script OberonPrint to delete the file when it is finished with it. This procedure will not terminate unless OberonPrint terminates. But OberonPrint may choose to spawn a background process for printing and return immediately. This module will cycle through more than 600 different print file names, thus there shouldn't be a problem with reuse of a file name which has not yet finished to print. *) cmd:=''; Amiga.GetSearchPath(cmd); Append(cmd,'Script/OberonPrint "'); Append(cmd,Amiga.PrinterName); Append(cmd,'" "'); Append(cmd,printFileName); Append(cmd,'" PSPrinter'); Amiga.DosCmd(cmd, "NIL:", i); IncPrintFile(printFileName) END END Close; PROCEDURE Init*; BEGIN PrinterDriver.Open := Open; PrinterDriver.UseListFont := UseListFont; PrinterDriver.ReplConst := ReplConst; PrinterDriver.ContString := ContString; PrinterDriver.String := String; PrinterDriver.ReplPattern := ReplPattern; PrinterDriver.Picture := Picture; PrinterDriver.Circle := Circle; PrinterDriver.Ellipse := Ellipse; PrinterDriver.Line := Line; PrinterDriver.UseColor := UseColor; PrinterDriver.Spline := Spline; PrinterDriver.Page := Page; PrinterDriver.Close := Close; resolution := DefaultResolution END Init; PROCEDURE SetHeader*; VAR s: Texts.Scanner; BEGIN ScanFirst(s); IF s.class IN {Texts.Name, Texts.String} THEN COPY(s.s, headerFileName) END END SetHeader; BEGIN headerFileName := defaultHeaderFileName; hexArray := "0123456789ABCDEF"; resolution := DefaultResolution; printFileName:="Oberon.Printfile.aa.ps"; FontsToMap[0]:="Syntax"; FontsToMap[1]:="Times"; FontsToMap[2]:="Courier"; styleNames[normal] := ".Roman"; styleNames[bold] := ".Bold"; styleNames[italic] := ".Italic"; styleNames[magic] := ".Magic" END PSPrinter.