Windows.Oberon.PSPrinter.Mod 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191
  1. (* ETH Oberon, Copyright 2001 ETH Zuerich Institut fuer Computersysteme, ETH Zentrum, CH-8092 Zuerich.
  2. Refer to the "General ETH Oberon System Source License" contract available at: http://www.oberon.ethz.ch/ *)
  3. MODULE PSPrinter IN Oberon; (** portable *) (*UNIX version: JT 11.5.90, RC 2.7.93, JS 29.4.9, Windows version: jm 20.12.95 *)
  4. (*
  5. wdm 2000-02-21 duplex printing: uses option "x"
  6. jm 20.12.95 EPS support added
  7. ps 4.8.96 added border to page (left, right: 2cm / top, bottom: 1.5 cm)
  8. *)
  9. IMPORT Files, Modules, Printer, Objects, Fonts, Texts, Strings, Oberon, Pictures;
  10. CONST
  11. N = 20; (* max spline points *)
  12. maxFonts = 64;
  13. headerFileName = "PSHeader.Text";
  14. bold = 0; italics = 1; medium = 2;
  15. oneup = 0; twoup = 1; fourup = 2; rotated = 3;
  16. TYPE
  17. Name* = ARRAY 32 OF CHAR;
  18. PSPrinter* = POINTER TO PSPrinterDesc;
  19. PSPrinterDesc* = RECORD (Printer.PrinterDesc)
  20. Escape*: PROCEDURE (P: Printer.Printer; s: ARRAY OF CHAR);
  21. printF*: Files.File;
  22. eps*: BOOLEAN; (** Is EPS output being written? *)
  23. pno*: INTEGER; (** Current page being printer on (starts with 1) *)
  24. l, t, r, b: LONGINT;
  25. sx, sy: INTEGER; (* current string pos *)
  26. mode, location: SHORTINT;
  27. duplex: BOOLEAN; (* Print duplex pages *)
  28. anonymous: BOOLEAN
  29. END;
  30. FontDesc = RECORD
  31. name: Name;
  32. used: ARRAY 8 OF SET;
  33. END;
  34. RealVector = ARRAY N OF REAL;
  35. Poly = RECORD a, b, c, d, t: REAL END ;
  36. PolyVector = ARRAY N OF Poly;
  37. TYPE
  38. FontDef = POINTER TO FontDefDesc;
  39. FontDefDesc = RECORD
  40. name: ARRAY 64 OF CHAR;
  41. family: ARRAY 32 OF CHAR;
  42. size: INTEGER;
  43. attr: CHAR;
  44. next: FontDef
  45. END;
  46. VAR
  47. fontTable: ARRAY maxFonts OF FontDesc;
  48. fontIndex, curFont: INTEGER;
  49. listFont: Name;
  50. headerT: Texts.Text;
  51. bodyF: Files.File;
  52. bodyR: Files.Rider;
  53. ppos: LONGINT;
  54. hexArray: ARRAY 17 OF CHAR;
  55. curR, curG, curB, setR, setG, setB: INTEGER;
  56. metric: Objects.Library;
  57. fontMapDict: FontDef;
  58. fontMapDictN: INTEGER;
  59. default: Objects.Name;
  60. (* -- Output procedures -- *)
  61. PROCEDURE Ch (VAR R: Files.Rider; ch: CHAR);
  62. BEGIN
  63. Files.Write(R, ch)
  64. END Ch;
  65. PROCEDURE Str (VAR R: Files.Rider; s: ARRAY OF CHAR);
  66. VAR i: INTEGER;
  67. BEGIN
  68. i := 0;
  69. WHILE s[i] # 0X DO Ch(R, s[i]); INC(i) END;
  70. END Str;
  71. PROCEDURE Int (VAR R: Files.Rider; i: LONGINT);
  72. VAR j: LONGINT;
  73. BEGIN
  74. IF i = 0 THEN Ch(R, "0") ELSIF i < 0 THEN i := -i; Ch(R, "-") END;
  75. j := 1;
  76. WHILE (i DIV j) # 0 DO j := j * 10 END;
  77. WHILE j >= 10 DO j := j DIV 10; Ch(R, CHR(30H + (i DIV j) MOD 10)) END;
  78. END Int;
  79. PROCEDURE Hex2(VAR R: Files.Rider; ch: CHAR);
  80. BEGIN
  81. Ch(R, hexArray[ORD(ch) DIV 16]);
  82. Ch(R, hexArray[ORD(ch) MOD 16]);
  83. END Hex2;
  84. PROCEDURE Real(VAR R: Files.Rider; x: REAL);
  85. VAR
  86. n, i, xi: INTEGER;
  87. d: ARRAY 4 OF CHAR;
  88. BEGIN
  89. xi := SHORT(ENTIER(x));
  90. IF x = xi THEN Int(R, xi); RETURN END;
  91. IF x < 0 THEN Files.Write(R, "-"); x := -x; xi := -xi END;
  92. Int(R, xi); Files.Write(R, "."); x := x-xi;
  93. n := SHORT(ENTIER(x*1000));
  94. i := 0;
  95. REPEAT
  96. d[i] := CHR(n MOD 10+30H); n := n DIV 10; INC(i)
  97. UNTIL i = 3;
  98. WHILE i > 0 DO DEC(i); Files.Write(R, d[i]) END
  99. END Real;
  100. PROCEDURE Ln(VAR R: Files.Rider);
  101. BEGIN
  102. Ch(R, 0DX);
  103. Ch(R, 0AX);
  104. END Ln;
  105. (* -- Error handling -- *)
  106. PROCEDURE Error(s0, s1: ARRAY OF CHAR);
  107. VAR error, f: ARRAY 32 OF CHAR;
  108. BEGIN COPY(s0, error); COPY(s1, f); HALT(99)
  109. END Error;
  110. (* -- Bounding Box -- *)
  111. PROCEDURE Min(x, y: LONGINT): LONGINT;
  112. BEGIN IF x < y THEN RETURN x ELSE RETURN y END
  113. END Min;
  114. (* Increase the size of the bounding box. *)
  115. PROCEDURE Box*(P: PSPrinter; x, y, w, h: LONGINT);
  116. BEGIN
  117. IF x < P.l THEN P.l := x END;
  118. IF x + w - 1 > P.r THEN P.r := x + w - 1 END;
  119. IF y < P.b THEN P.b := y END;
  120. IF y + h - 1 > P.t THEN P.t := y + h - 1 END;
  121. END Box;
  122. (* -- Font Mapping -- *)
  123. PROCEDURE SetMappedFont(VAR fontR: Files.Rider; fname: ARRAY OF CHAR);
  124. VAR family: ARRAY 7 OF CHAR;
  125. BEGIN
  126. COPY(fname, family);
  127. Ch(fontR, "/"); Str(fontR, fname);
  128. IF (family = "Syntax") OR (family = "Oberon") OR (family = "Default") THEN Str(fontR, " DefineSMapFont")
  129. ELSE Str(fontR, " DefineMapFont") END;
  130. Ln(fontR); Ln(fontR);
  131. END SetMappedFont;
  132. PROCEDURE SetBitmapFont(VAR fontR, R: Files.Rider; fd: FontDesc; pRes: INTEGER);
  133. TYPE
  134. RunRec = RECORD beg, end: INTEGER END;
  135. Metrics = RECORD dx, x, y, w, h: INTEGER END;
  136. VAR
  137. ch: CHAR;
  138. pixmapDX, n, b: LONGINT;
  139. k, m: INTEGER;
  140. height, minX, maxX, minY, maxY: INTEGER;
  141. nOfBoxes, nOfRuns: INTEGER;
  142. run: ARRAY 16 OF RunRec;
  143. metrics: ARRAY 256 OF Metrics;
  144. PROCEDURE Flip(ch: CHAR): CHAR;
  145. VAR i, s, d: INTEGER;
  146. BEGIN
  147. i := 0; s := ORD(ch); d := 0;
  148. WHILE i < 8 DO
  149. IF s MOD 2 = 1 THEN d := d * 2 + 1 ELSE d := d * 2 END;
  150. s := s DIV 2;
  151. INC(i)
  152. END;
  153. RETURN CHR(d);
  154. END Flip;
  155. PROCEDURE Name(m: INTEGER);
  156. BEGIN
  157. CASE m OF
  158. | 9: Str(fontR, "tab")
  159. | 32: Str(fontR, "space")
  160. | 33: Str(fontR, "exclam")
  161. | 34: Str(fontR, "quotedbl")
  162. | 35: Str(fontR, "numbersign")
  163. | 36: Str(fontR, "dollar")
  164. | 37: Str(fontR, "percent")
  165. | 38: Str(fontR, "ampersand")
  166. | 39: Str(fontR, "quotesingle")
  167. | 40: Str(fontR, "parenleft")
  168. | 41: Str(fontR, "parenright")
  169. | 42: Str(fontR, "asterisk")
  170. | 43: Str(fontR, "plus")
  171. | 44: Str(fontR, "comma")
  172. | 45: Str(fontR, "minus")
  173. | 46: Str(fontR, "period")
  174. | 47: Str(fontR, "slash")
  175. | 48: Str(fontR, "zero")
  176. | 49: Str(fontR, "one")
  177. | 50: Str(fontR, "two")
  178. | 51: Str(fontR, "three")
  179. | 52: Str(fontR, "four")
  180. | 53: Str(fontR, "five")
  181. | 54: Str(fontR, "six")
  182. | 55: Str(fontR, "seven")
  183. | 56: Str(fontR, "eight")
  184. | 57: Str(fontR, "nine")
  185. | 58: Str(fontR, "colon")
  186. | 59: Str(fontR, "semicolon")
  187. | 60: Str(fontR, "less")
  188. | 61: Str(fontR, "equal")
  189. | 62: Str(fontR, "greater")
  190. | 63: Str(fontR, "question")
  191. | 64: Str(fontR, "at")
  192. | 65..90: Ch(fontR, CHR(m))
  193. | 91: Str(fontR, "bracketleft")
  194. | 92: Str(fontR, "backslash")
  195. | 93: Str(fontR, "bracketright")
  196. | 94: Str(fontR, "arrowup")
  197. | 95: Str(fontR, "underscore")
  198. | 96: Str(fontR, "grave")
  199. | 97..122: Ch(fontR, CHR(m))
  200. | 123: Str(fontR, "braceleft")
  201. | 124: Str(fontR, "bar")
  202. | 125: Str(fontR, "braceright")
  203. | 126: Str(fontR, "tilde")
  204. | 128: Str(fontR, "Adieresis")
  205. | 129: Str(fontR, "Odieresis")
  206. | 130: Str(fontR, "Udieresis")
  207. | 131: Str(fontR, "adieresis")
  208. | 132: Str(fontR, "odieresis")
  209. | 133: Str(fontR, "udieresis")
  210. | 134: Str(fontR, "acircumflex")
  211. | 135: Str(fontR, "ecircumflex")
  212. | 136: Str(fontR, "icircumflex")
  213. | 137: Str(fontR, "oicircumflex")
  214. | 138: Str(fontR, "uicircumflex")
  215. | 139: Str(fontR, "agrave")
  216. | 140: Str(fontR, "egrave")
  217. | 141: Str(fontR, "igrave")
  218. | 142: Str(fontR, "ograve")
  219. | 143: Str(fontR, "ugrave")
  220. | 144: Str(fontR, "eacute")
  221. | 145: Str(fontR, "edieresis")
  222. | 146: Str(fontR, "idieresis")
  223. | 147: Str(fontR, "ccedilla")
  224. | 148: Str(fontR, "aacute")
  225. | 149: Str(fontR, "ntilde")
  226. | 150: Str(fontR, "germandbls")
  227. | 155: Str(fontR, "endash")
  228. | 159: Str(fontR, "hyphen")
  229. ELSE
  230. Str(fontR, "ascii");
  231. Ch(fontR, CHR(30H + (m DIV 100) MOD 10));
  232. Ch(fontR, CHR(30H + (m DIV 10) MOD 10));
  233. Ch(fontR, CHR(30H + m MOD 10))
  234. END
  235. END Name;
  236. BEGIN
  237. Str(fontR, "% Conversion of the Oberon font "); Str(fontR, fd.name); Ln(fontR);
  238. Files.Read(R, ch);
  239. IF ch = Fonts.FontId THEN
  240. Files.Read(R, ch); Str(fontR, "% abstraction: "); Int(fontR, ORD(ch));
  241. Files.Read(R, ch); Str(fontR, ", family: "); Ch(fontR, ch);
  242. Files.Read(R, ch); Str(fontR, ", variant: "); Int(fontR, ORD(ch)); Ln(fontR);
  243. Files.ReadInt(R, height); Str(fontR, "% height: "); Int(fontR, height); Ln(fontR); Ln(fontR);
  244. Files.ReadInt(R, minX); Files.ReadInt(R, maxX);
  245. Files.ReadInt(R, minY); Files.ReadInt(R, maxY);
  246. Files.ReadInt(R, nOfRuns);
  247. nOfBoxes := 0; k := 0;
  248. WHILE k # nOfRuns DO
  249. Files.ReadInt(R, run[k].beg); Files.ReadInt(R, run[k].end);
  250. INC(nOfBoxes, run[k].end - run[k].beg);
  251. INC(k)
  252. END;
  253. Str(fontR, "9 dict begin"); Ln(fontR); Ln(fontR);
  254. Str(fontR, "/FontType 3 def"); Ln(fontR);
  255. Str(fontR, "/FontMatrix [ 72 "); Int(fontR, pRes); Str(fontR, " div "); Str(fontR, " factor1 div 0 0 ");
  256. Str(fontR, "72 "); Int(fontR, pRes); Str(fontR, " div "); Str(fontR, " factor2 div 0 0");
  257. Str(fontR, "] def"); Ln(fontR);
  258. Str(fontR, "/FontBBox [");
  259. Int(fontR, minX); Ch(fontR, " ");
  260. Int(fontR, minY); Ch(fontR, " ");
  261. Int(fontR, maxX); Ch(fontR, " ");
  262. Int(fontR, maxY);
  263. Str(fontR, "] def"); Ln(fontR); Ln(fontR);
  264. Str(fontR, "/Encoding 256 array def"); Ln(fontR);
  265. Str(fontR, "0 1 255 {Encoding exch /.notdef put} for"); Ln(fontR);
  266. Str(fontR, "Encoding OberonEncoding /Encoding exch def"); Ln(fontR);
  267. Ln(fontR);
  268. Str(fontR, "/CharData "); Int(fontR, nOfBoxes+1);
  269. Str(fontR, " dict def"); Ln(fontR);
  270. Str(fontR, "CharData begin"); Ln(fontR);
  271. k := 0; m := 0;
  272. WHILE k < nOfRuns DO
  273. m := run[k].beg;
  274. WHILE m < run[k].end DO
  275. Files.ReadInt(R, metrics[m].dx);
  276. Files.ReadInt(R, metrics[m].x); Files.ReadInt(R, metrics[m].y);
  277. Files.ReadInt(R, metrics[m].w); Files.ReadInt(R, metrics[m].h);
  278. INC(m);
  279. END;
  280. INC(k)
  281. END;
  282. Str(fontR, "/.notdef"); Str(fontR, " [");
  283. Int(fontR, metrics[32].w); Str(fontR, " 0 0 0 0 1 1 0 0"); Ln(fontR);
  284. Str(fontR, "<>] bdef"); Ln(fontR);
  285. k := 0; m := 0;
  286. WHILE k < nOfRuns DO
  287. m := run[k].beg;
  288. WHILE m < run[k].end DO
  289. IF m MOD 32 IN fd.used[m DIV 32] THEN
  290. Str(fontR, "/"); Name(m); Str(fontR, " [");
  291. Int(fontR, metrics[m].dx); Str(fontR, " ");
  292. Int(fontR, metrics[m].x); Str(fontR, " "); Int(fontR, metrics[m].y); Str(fontR, " ");
  293. Int(fontR, metrics[m].x + metrics[m].w); Str(fontR, " ");
  294. Int(fontR, metrics[m].y + metrics[m].h); Str(fontR, " ");
  295. IF metrics[m].w > 0 THEN Int(fontR, metrics[m].w); ELSE Int(fontR, 1) END; Str(fontR, " ");
  296. IF metrics[m].h > 0 THEN Int(fontR, metrics[m].h); ELSE Int(fontR, 1) END; Str(fontR, " ");
  297. Int(fontR, -metrics[m].x); Str(fontR, " "); Int(fontR, -metrics[m].y); Ln(fontR);
  298. Str(fontR, "<");
  299. pixmapDX := (metrics[m].w + 7) DIV 8;
  300. n := pixmapDX * metrics[m].h;
  301. b := 0;
  302. WHILE b < n DO
  303. Files.Read(R, ch); Hex2(fontR, Flip(ch));
  304. INC(b);
  305. IF b MOD 32 = 0 THEN Ln(fontR); Str(fontR, " ") END
  306. END;
  307. Str(fontR, ">] bdef"); Ln(fontR);
  308. ELSE
  309. n := (metrics[m].w + 7) DIV 8 * metrics[m].h;
  310. b := 0; WHILE b < n DO Files.Read(R, ch); INC(b) END;
  311. END;
  312. INC(m);
  313. END;
  314. INC(k)
  315. END;
  316. Str(fontR, " end"); Ln(fontR); Ln(fontR);
  317. Str(fontR, "/BuildGlyph {GlobalBuildGlyph} bdef"); Ln(fontR);
  318. Str(fontR, "/BuildChar {GlobalBuildChar} bdef"); Ln(fontR); Ln(fontR);
  319. Str(fontR, "/imageMaskMatrix [1 0 0 1 0 0] bdef"); Ln(fontR); Ln(fontR);
  320. Str(fontR, "currentdict"); Ln(fontR); Ln(fontR);
  321. Str(fontR, "end"); Ln(fontR); Ln(fontR);
  322. Ch(fontR, "/"); Str(fontR, fd.name);
  323. Str(fontR, " exch definefont pop"); Ln(fontR); Ln(fontR);
  324. END;
  325. END SetBitmapFont;
  326. PROCEDURE DefineFont(VAR fontR: Files.Rider; fd: FontDesc; echo: BOOLEAN);
  327. VAR
  328. family, name: ARRAY 32 OF CHAR;
  329. i, size, dpi: INTEGER;
  330. f: Files.File; R: Files.Rider;
  331. fontDef: FontDef;
  332. attr: CHAR;
  333. BEGIN
  334. dpi := SHORT(914400 DIV Printer.current.Unit);
  335. COPY(fd.name, name); i := 0; size := 0;
  336. WHILE (name[i] # 0X) & (name[i] # ".") & ((name[i] < "0") OR (name[i] > "9")) DO
  337. family[i] := name[i]; INC(i)
  338. END;
  339. family[i] := 0X;
  340. size := 0;
  341. WHILE (name[i] >= "0") & (name[i] <= "9") DO size := size * 10 + ORD(name[i]) - 30H; INC(i) END;
  342. attr := 0X;
  343. WHILE (name[i] # 0X) & (name[i] # ".") DO attr := CAP(name[i]); INC(i) END;
  344. fontDef := fontMapDict;
  345. WHILE (fontDef # NIL) & ~((fontDef.size = size) & (fontDef.attr = attr) & (fontDef.family = family)) DO
  346. fontDef := fontDef.next
  347. END;
  348. IF fontDef = NIL THEN
  349. NEW(fontDef); fontDef.next := fontMapDict; fontMapDict := fontDef; INC(fontMapDictN);
  350. COPY(name, fontDef.name); COPY(family, fontDef.family);
  351. fontDef.size := size; fontDef.attr := attr
  352. END;
  353. IF ~echo THEN RETURN END;
  354. IF (name[i] # ".") OR (name[i+1] # "S") OR (name[i+2] # "c") OR (name[i+3] # "n") THEN
  355. SetMappedFont (fontR, fd.name);
  356. ELSE
  357. name[i+1] := "P"; name[i+2] := "r"; name[i+3] := CHR((dpi DIV 100)+ORD("0"));
  358. f := Files.Old(name);
  359. IF f = NIL THEN
  360. SetMappedFont (fontR, fd.name);
  361. ELSE
  362. Files.Set(R, f, 0); SetBitmapFont(fontR, R, fd, dpi)
  363. END;
  364. END;
  365. END DefineFont;
  366. (* -- Metric Font loading -- *)
  367. PROCEDURE ParseName (VAR name, family: ARRAY OF CHAR; VAR size: LONGINT; VAR style: SET; VAR class: ARRAY OF CHAR);
  368. VAR i, j: INTEGER;
  369. BEGIN
  370. size := 0; style := {}; i := 0;
  371. WHILE (name[i] > "9") OR (name[i] = " ") DO family[i] := name[i]; INC(i) END;
  372. family[i] := 0X;
  373. WHILE ("0" <= name[i]) & (name[i] <= "9") DO size := 10*size + (ORD(name[i]) - 30H); INC(i) END;
  374. WHILE (name[i] # 0X) & (name[i] # ".") DO
  375. CASE CAP(name[i]) OF
  376. | "I": INCL(style, italics); name[i] := "i"
  377. | "B": INCL(style, bold); name[i] := "b"
  378. | "M": INCL(style, medium); name[i] := "m"
  379. ELSE
  380. END;
  381. INC(i)
  382. END;
  383. j := 0;
  384. INC(i); WHILE (name[i] # 0X) & (name[i] # ".") DO class[j] := name[i]; INC(i); INC(j) END;
  385. class[j] := 0X;
  386. END ParseName;
  387. (* -- Exported Procedures -- *)
  388. PROCEDURE GetDim(P: Printer.Printer; label: ARRAY OF CHAR; def: INTEGER; VAR val: INTEGER);
  389. VAR v: REAL; S: Texts.Scanner;
  390. BEGIN
  391. Oberon.OpenScanner(S, label);
  392. IF S.class IN {Texts.Int, Texts.Real} THEN
  393. IF S.class = Texts.Int THEN v := S.i
  394. ELSE v := S.x
  395. END;
  396. Texts.Scan(S);
  397. IF S.class IN {Texts.Name, Texts.String} THEN
  398. IF S.s = "cm" THEN v := v*360000.0
  399. ELSIF S.s = "mm" THEN v := v*36000.0
  400. ELSIF S.s = "in" THEN v := v*36000.0*25.4
  401. ELSE v := v*36000.0 (* default mm *)
  402. END
  403. ELSE v := v*36000.0 (* default mm *)
  404. END;
  405. val := SHORT(ENTIER(v/P.Unit + 0.5))
  406. ELSE
  407. val := SHORT(ENTIER(def*36000.0/P.Unit + 0.5))
  408. END
  409. END GetDim;
  410. PROCEDURE Swap(VAR x, y: INTEGER);
  411. VAR t: INTEGER;
  412. BEGIN
  413. t := x; x := y; y := t
  414. END Swap;
  415. PROCEDURE InitMetrics*(P: Printer.Printer);
  416. VAR S: Texts.Scanner;
  417. BEGIN
  418. Oberon.OpenScanner(S, "Printer.PSPrinter.Resolution");
  419. IF S.class # Texts.Int THEN S.i := 300 END; (* default *)
  420. P.Unit := 914400 DIV S.i; P.Depth := 24;
  421. GetDim(P, "Printer.PSPrinter.Width", 210, P.Width);
  422. GetDim(P, "Printer.PSPrinter.Height", 297, P.Height);
  423. GetDim(P, "Printer.PSPrinter.LeftMargin", 20, P.FrameX);
  424. GetDim(P, "Printer.PSPrinter.RightMargin", 20, P.FrameW);
  425. P.FrameW := P.Width-P.FrameX-P.FrameW;
  426. GetDim(P, "Printer.PSPrinter.BottomMargin", 15, P.FrameY);
  427. GetDim(P, "Printer.PSPrinter.TopMargin", 15, P.FrameH);
  428. P.FrameH := P.Height-P.FrameY-P.FrameH;
  429. IF P(PSPrinter).mode = rotated THEN
  430. Swap(P.Width, P.Height); Swap(P.FrameX, P.FrameY); Swap(P.FrameW, P.FrameH)
  431. END
  432. END InitMetrics;
  433. PROCEDURE GetSuffix(VAR str(** in *), suf(** out *): ARRAY OF CHAR);
  434. VAR i, j, dot: LONGINT;
  435. BEGIN
  436. dot := -1; i := 0;
  437. WHILE str[i] # 0X DO
  438. IF str[i] = "." THEN dot := i END;
  439. INC(i)
  440. END;
  441. j := 0;
  442. IF dot > 0 THEN
  443. i := dot+1;
  444. WHILE str[i] # 0X DO
  445. suf[j] := str[i]; INC(j); INC(i)
  446. END
  447. END;
  448. suf[j] := 0X
  449. END GetSuffix;
  450. PROCEDURE SetColor;
  451. BEGIN
  452. IF (setR # curR) OR (setG # curG) OR (setB # curB) THEN
  453. setR := curR; setG := curG; setB := curB;
  454. Real(bodyR, setR/255); Ch(bodyR, " ");
  455. Real(bodyR, setG/255); Ch(bodyR, " ");
  456. Real(bodyR, setB/255); Ch(bodyR, " ");
  457. Str(bodyR, "u ");
  458. Ln(bodyR)
  459. END
  460. END SetColor;
  461. PROCEDURE ResetColor;
  462. BEGIN
  463. curR := 0; curG := 0; curB := 0;
  464. setR := 0; setG := 0; setB := 0
  465. END ResetColor;
  466. PROCEDURE Open*(P: Printer.Printer; printer, options: ARRAY OF CHAR);
  467. VAR suffix: ARRAY 32 OF CHAR; i: LONGINT;
  468. BEGIN
  469. WITH P: PSPrinter DO
  470. ResetColor;
  471. P.res := 1; (* no such printer *)
  472. P.printF := Files.New(printer);
  473. IF P.printF = NIL THEN
  474. P.printF := Files.New(""); P.anonymous := TRUE
  475. ELSE
  476. P.anonymous := FALSE
  477. END;
  478. GetSuffix(printer, suffix);
  479. P.eps := (suffix = "EPS") OR (suffix = "eps");
  480. i := 0; P.mode := oneup; P.location := 0;
  481. WHILE (options[i] # 0X) & (options[i] # Oberon.OptionChar) DO
  482. IF options[i] = "l" THEN P.mode := twoup
  483. ELSIF options[i] = "d" THEN P.mode := fourup
  484. ELSIF options[i] = "e" THEN P.eps := TRUE
  485. ELSIF options[i] = "r" THEN P.mode := rotated
  486. ELSIF options[i] = "x" THEN P.duplex := TRUE
  487. END;
  488. INC(i)
  489. END;
  490. InitMetrics(P);
  491. fontMapDict := NIL; fontMapDictN := 0;
  492. P.l := MAX(LONGINT); P.r := MIN(LONGINT); P.t := MIN(LONGINT); P.b := MAX(LONGINT);
  493. NEW(headerT); Texts.Open(headerT, headerFileName);
  494. IF headerT.len > 0 THEN
  495. bodyF := Files.New(""); Files.Set(bodyR, bodyF, 0);
  496. fontIndex := -1; curFont := -1; listFont := ""; ppos := 0; P.pno := 1;
  497. P.res := 0
  498. ELSE
  499. Error("file not found", headerFileName)
  500. END
  501. END
  502. END Open;
  503. PROCEDURE UseListFont*(P: Printer.Printer; name: ARRAY OF CHAR);
  504. BEGIN
  505. COPY(name, listFont); curFont := -1
  506. END UseListFont;
  507. (** Don't forget to update the bounding box of eps files by calling procedure Box. *)
  508. PROCEDURE Escape*(P: Printer.Printer; s: ARRAY OF CHAR);
  509. BEGIN
  510. WITH P: PSPrinter DO
  511. (* Don't make more that one page when making eps *)
  512. IF P.eps & (P.pno > 1) THEN RETURN END;
  513. SetColor;
  514. Str(bodyR, s)
  515. END
  516. END Escape;
  517. PROCEDURE ReplConst*(P: Printer.Printer; x, y, w, h: INTEGER);
  518. BEGIN
  519. WITH P: PSPrinter DO
  520. (* Don't make more that one page when making eps *)
  521. IF P.eps & (P.pno > 1) THEN RETURN END;
  522. IF (w > 0) & (h > 0) THEN
  523. SetColor;
  524. Box(P, x, y, w, h);
  525. Int(bodyR, x+1); Ch(bodyR, " ");
  526. Int(bodyR, y); Ch(bodyR, " ");
  527. Int(bodyR, w-1); Ch(bodyR, " ");
  528. Int(bodyR, h-1); Str(bodyR, " l"); Ln(bodyR);
  529. END
  530. END
  531. END ReplConst;
  532. PROCEDURE StringSize(VAR s: ARRAY OF CHAR; fnt: Fonts.Font; VAR w, h, dsr: INTEGER);
  533. VAR p: INTEGER; obj: Objects.Object;
  534. BEGIN
  535. w := 0; h := 0; dsr := 0;
  536. p := 0;
  537. IF (metric = NIL) OR (fnt.name # metric.name) THEN metric := Printer.GetMetric(fnt) END;
  538. IF (metric # NIL) & (metric(Fonts.Font).type = Fonts.metric) THEN
  539. WHILE s[p] # 0X DO
  540. metric.GetObj(metric, ORD(s[p]), obj);
  541. INC(w, obj(Fonts.Char).dx);
  542. INC(p)
  543. END;
  544. h := metric(Fonts.Font).height;
  545. dsr := ABS(metric(Fonts.Font).minY);
  546. END
  547. END StringSize;
  548. PROCEDURE ContString*(P: Printer.Printer; s: ARRAY OF CHAR; fnt: Fonts.Font);
  549. VAR fNo, i, n, w, h, dsr: INTEGER; ch: CHAR; family: ARRAY 7 OF CHAR;
  550. PROCEDURE Use(ch: CHAR);
  551. BEGIN
  552. INCL(fontTable[curFont].used[ORD(ch) DIV 32], ORD(ch) MOD 32);
  553. END Use;
  554. BEGIN
  555. WITH P: PSPrinter DO
  556. (* Don't make more that one page when making eps *)
  557. IF P.eps & (P.pno > 1) THEN RETURN END;
  558. SetColor;
  559. StringSize(s, fnt, w, h, dsr);
  560. Box(P, P.sx - dsr, P.sy, w, h);
  561. INC(P.sx, w);
  562. IF (curFont < 0) OR (fontTable[curFont].name # fnt.name) THEN
  563. COPY(fnt.name, fontTable[fontIndex+1].name);
  564. i := 0; WHILE i < 8 DO fontTable[fontIndex+1].used[i] := {}; INC(i) END;
  565. fNo := 0;
  566. WHILE fontTable[fNo].name # fnt.name DO INC(fNo) END;
  567. IF fNo > fontIndex THEN (* DefineFont(fname); *) fontIndex := fNo END;
  568. curFont := fNo; Ch(bodyR, "(");
  569. IF fontTable[curFont].name = listFont THEN
  570. Str(bodyR, "Courier8.Scn.Fnt")
  571. ELSE
  572. Str(bodyR, fontTable[curFont].name)
  573. END;
  574. Str(bodyR, ") f ")
  575. END;
  576. Ch(bodyR, "(");
  577. i := 0; ch := s[0];
  578. WHILE ch # 0X DO
  579. CASE ch OF
  580. | "(", ")", "\": Ch(bodyR, "\"); Ch(bodyR, ch); Use(ch);
  581. | 9X: Str(bodyR, " "); Use(" ") (* or Str("\tab") *)
  582. | 80X..95X, 0ABX:
  583. Str(bodyR, "\2"); n := ORD(ch)-128;
  584. Ch(bodyR, CHR(n DIV 8 + 48)); Ch(bodyR, CHR(n MOD 8 + 48)); Use(ch)
  585. | 9FX: COPY(fontTable[curFont].name, family);
  586. IF family = "Courie" THEN Ch(bodyR, " ") ELSE Str(bodyR, " ") END; Use(" ");
  587. ELSE
  588. Ch(bodyR, ch); Use(ch);
  589. END ;
  590. INC(i); ch := s[i];
  591. END;
  592. Str(bodyR, ") s"); Ln(bodyR)
  593. END
  594. END ContString;
  595. PROCEDURE String*(P: Printer.Printer; x, y: INTEGER; s: ARRAY OF CHAR; fnt: Fonts.Font);
  596. VAR w, h, dsr: INTEGER;
  597. BEGIN
  598. WITH P: PSPrinter DO
  599. (* Don't make more that one page when making eps *)
  600. IF P.eps & (P.pno > 1) THEN RETURN END;
  601. SetColor;
  602. StringSize(s, fnt, w, h, dsr);
  603. Box(P, x - dsr, y, w, h);
  604. P.sx := x + w; P.sy := y;
  605. Int(bodyR, x); Ch(bodyR, " ");
  606. Int(bodyR, y); Str(bodyR, " m "); ContString(P, s, fnt)
  607. END
  608. END String;
  609. PROCEDURE ReplPattern*(P: Printer.Printer; x, y, w, h, col: INTEGER);
  610. BEGIN
  611. WITH P: PSPrinter DO
  612. (* Don't make more that one page when making eps *)
  613. IF P.eps & (P.pno > 1) THEN RETURN END;
  614. SetColor;
  615. Box(P, x, y, w, h);
  616. Int(bodyR, x+1); Ch(bodyR, " ");
  617. Int(bodyR, y); Ch(bodyR, " ");
  618. Int(bodyR, w-1); Ch(bodyR, " ");
  619. Int(bodyR, h-1); Ch(bodyR, " ");
  620. Int(bodyR, col); Str(bodyR, " b"); Ln(bodyR)
  621. END
  622. END ReplPattern;
  623. (* mode is not used *)
  624. PROCEDURE Picture*(P: Printer.Printer; pict: Pictures.Picture; sx, sy, sw, sh, dx, dy, dw, dh, mode: INTEGER);
  625. VAR
  626. x, y: INTEGER;
  627. n, h0, h1, k, i: INTEGER;
  628. h: ARRAY 128 OF INTEGER;
  629. PROCEDURE WColTab(n: INTEGER);
  630. VAR i, r, g, b: INTEGER;
  631. BEGIN
  632. i := 0; WHILE i < n DO Pictures.GetColor(pict, i, r, g, b); Hex2(bodyR, CHR(r)); INC(i) END; Ln(bodyR);
  633. i := 0; WHILE i < n DO Pictures.GetColor(pict, i, r, g, b); Hex2(bodyR, CHR(g)); INC(i) END; Ln(bodyR);
  634. i := 0; WHILE i < n DO Pictures.GetColor(pict, i, r, g, b); Hex2(bodyR, CHR(b)); INC(i) END; Ln(bodyR);
  635. END WColTab;
  636. PROCEDURE H(n: INTEGER);
  637. VAR d0, d1: INTEGER;
  638. BEGIN
  639. d0 := n MOD 16; IF d0 > 9 THEN INC(d0, 7) END;
  640. d1 := n DIV 16; IF d1 > 9 THEN INC(d1, 7) END;
  641. Files.Write(bodyR, CHR(d1+30H)); Files.Write(bodyR, CHR(d0+30H))
  642. END H;
  643. PROCEDURE Out;
  644. BEGIN
  645. IF n > 0 THEN
  646. IF n = 1 THEN H(0); H(h[0])
  647. ELSIF (n = 2) & (h[0] = h[1]) THEN H(81H); H(h[0])
  648. ELSE H(n-1); i := 0; WHILE i < n DO H(h[i]); INC(i) END
  649. END;
  650. n := 0
  651. END;
  652. WHILE k > 128 DO H(127+128); H(h0); DEC(k, 128) END;
  653. H(127+k); H(h0)
  654. END Out;
  655. BEGIN
  656. WITH P: PSPrinter DO
  657. (* Don't make more that one page when making eps *)
  658. IF P.eps & (P.pno > 1) THEN RETURN END;
  659. Box(P, dx, dy, dw, dh);
  660. Str(bodyR, "gsave ");
  661. Int(bodyR, dx); Ch(bodyR, " ");
  662. Int(bodyR, dy);
  663. Str(bodyR, " translate ");
  664. Real(bodyR, dw/sw); Ch(bodyR, " "); Real(bodyR, dh/sh); Str(bodyR, " scale ");
  665. Int(bodyR, sw); Ch(bodyR, " "); Int(bodyR, sh);
  666. Str(bodyR, " rlepic ");
  667. WColTab(256);
  668. y := sy + sh - 1;
  669. WHILE y >= sy DO
  670. n := 0; x := sx;
  671. h0 := Pictures.Get(pict, x, y); INC(x); k := 1;
  672. WHILE x < sx + sw DO
  673. h1 := Pictures.Get(pict, x, y); h[n] := h1;
  674. IF h1 = h0 THEN INC(k)
  675. ELSE
  676. IF k < 3 THEN
  677. IF n + k >= 128 THEN H(127);
  678. i := 0; WHILE i < n DO H(h[i]); INC(i) END;
  679. i := 0; WHILE n + i < 128 DO H(h0); INC(i); DEC(k) END;
  680. n := 0
  681. END;
  682. WHILE k > 0 DO DEC(k); h[n] := h0; INC(n) END
  683. ELSE Out
  684. END;
  685. h0 := h1; k := 1
  686. END;
  687. INC(x)
  688. END;
  689. Out;
  690. DEC(y); Ln(bodyR)
  691. END;
  692. Ln(bodyR);
  693. Str(bodyR, "grestore "); Ln(bodyR)
  694. END
  695. END Picture;
  696. PROCEDURE Circle*(P: Printer.Printer; x0, y0, r: INTEGER);
  697. BEGIN
  698. WITH P: PSPrinter DO
  699. (* Don't make more that one page when making eps *)
  700. IF P.eps & (P.pno > 1) THEN RETURN END;
  701. SetColor;
  702. Box(P, x0 - r, y0 - r, r * 2, r * 2);
  703. Int(bodyR, x0); Ch(bodyR, " ");
  704. Int(bodyR, y0); Ch(bodyR, " ");
  705. Int(bodyR, r); Ch(bodyR, " ");
  706. Int(bodyR, r); Str(bodyR, " c");
  707. Ln(bodyR)
  708. END
  709. END Circle;
  710. PROCEDURE Ellipse*(P: Printer.Printer; x0, y0, a, b: INTEGER);
  711. BEGIN
  712. WITH P: PSPrinter DO
  713. (* Don't make more that one page when making eps *)
  714. IF P.eps & (P.pno > 1) THEN RETURN END;
  715. SetColor;
  716. Box(P, x0 - a, y0 - b, a * 2 , b * 2);
  717. Int(bodyR, x0); Ch(bodyR, " ");
  718. Int(bodyR, y0); Ch(bodyR, " ");
  719. Int(bodyR, a); Ch(bodyR, " ");
  720. Int(bodyR, b); Str(bodyR, " c");
  721. Ln(bodyR)
  722. END
  723. END Ellipse;
  724. PROCEDURE Line*(P: Printer.Printer; x0, y0, x1, y1: INTEGER);
  725. BEGIN
  726. WITH P: PSPrinter DO
  727. (* Don't make more that one page when making eps *)
  728. IF P.eps & (P.pno > 1) THEN RETURN END;
  729. SetColor;
  730. Box(P, Min(x0, x1), Min(y0, y1), ABS(x1 - x0), ABS(y1 - y0));
  731. Int(bodyR, x0); Ch(bodyR, " ");
  732. Int(bodyR, y0); Ch(bodyR, " ");
  733. Int(bodyR, x1-x0); Ch(bodyR, " ");
  734. Int(bodyR, y1-y0); Str(bodyR, " x");
  735. Ln(bodyR)
  736. END
  737. END Line;
  738. PROCEDURE UseColor*(P: Printer.Printer; red, green, blue: INTEGER);
  739. BEGIN
  740. curR := red; curG := green; curB := blue
  741. END UseColor;
  742. (* -- Spline computation -- *)
  743. PROCEDURE SolveTriDiag(VAR a, b, c, y: RealVector; n: INTEGER);
  744. VAR i: INTEGER; t, tt: REAL;
  745. BEGIN (*a, b, c of tri-diag matrix T; solve Ty' = y for y', assign y' to y*)
  746. i := 1;
  747. WHILE i < n DO t := y[i-1]; y[i] := y[i] - c[i-1]*t; INC(i) END ;
  748. i := n-1; y[i] := y[i]/a[i];
  749. WHILE i > 0 DO DEC(i); t := a[i]; tt := b[i]*y[i+1]; y[i] := (y[i] - tt)/t END
  750. END SolveTriDiag;
  751. PROCEDURE OpenSpline(VAR x, y, d: RealVector; n: INTEGER);
  752. VAR i: INTEGER; d1, d2: REAL;
  753. a, b, c: RealVector;
  754. BEGIN (*from x, y compute d = y'*)
  755. b[0] := 1.0/(x[1] - x[0]); a[0] := 2.0*b[0]; c[0] := b[0];
  756. d1 := (y[1] - y[0])*3.0*b[0]*b[0]; d[0] := d1; i := 1;
  757. WHILE i < n-1 DO
  758. b[i] := 1.0/(x[i+1] - x[i]);
  759. a[i] := 2.0*(c[i-1] + b[i]);
  760. c[i] := b[i];
  761. d2 := (y[i+1] - y[i])*3.0*b[i]*b[i];
  762. d[i] := d1 + d2; d1 := d2; INC(i)
  763. END ;
  764. a[i] := 2.0*b[i-1]; d[i] := d1; i := 0;
  765. WHILE i < n-1 DO c[i] := c[i]/a[i]; a[i+1] := a[i+1] - c[i]*b[i]; INC(i) END ;
  766. SolveTriDiag(a, b, c, d, n)
  767. END OpenSpline;
  768. PROCEDURE ClosedSpline(VAR x, y, d: RealVector; n: INTEGER);
  769. VAR i: INTEGER; d1, d2, hn, dn: REAL;
  770. a, b, c, w: RealVector;
  771. BEGIN (*from x, y compute d = y'*)
  772. hn := 1.0/(x[n-1] - x[n-2]);
  773. dn := (y[n-1] - y[n-2])*3.0*hn*hn;
  774. b[0] := 1.0/(x[1] - x[0]);
  775. a[0] := 2.0*b[0] + hn;
  776. c[0] := b[0];
  777. d1 := (y[1] - y[0])*3.0*b[0]*b[0]; d[0] := dn + d1;
  778. w[0] := 1.0; i := 1;
  779. WHILE i < n-2 DO
  780. b[i] := 1.0/(x[i+1] - x[i]);
  781. a[i] := 2.0*(c[i-1] + b[i]);
  782. c[i] := b[i];
  783. d2 := (y[i+1] - y[i])*3.0*b[i]*b[i]; d[i] := d1 + d2; d1 := d2;
  784. w[i] := 0; INC(i)
  785. END ;
  786. a[i] := 2.0*b[i-1] + hn; d[i] := d1 + dn;
  787. w[i] := 1.0; i := 0;
  788. WHILE i < n-2 DO c[i] := c[i]/a[i]; a[i+1] := a[i+1] - c[i]*b[i]; INC(i) END ;
  789. SolveTriDiag(a, b, c, d, n-1); SolveTriDiag(a, b, c, w, n-1);
  790. d1 := (d[0] + d[i])/(w[0] + w[i] + x[i+1] - x[i]); i := 0;
  791. WHILE i < n-1 DO d[i] := d[i] - d1*w[i]; INC(i) END ;
  792. d[i] := d[0]
  793. END ClosedSpline;
  794. PROCEDURE PrintPoly(P: PSPrinter; VAR p, q: Poly; lim: REAL);
  795. VAR x0, y0, x1, y1, x2, y2, x3, y3: REAL;
  796. xx0, yy0, xx1, yy1, xx2, yy2, xx3, yy3: LONGINT;
  797. BEGIN
  798. x0 := p.d;
  799. y0 := q.d;
  800. x1 := x0 + p.c*lim/3.0;
  801. y1 := y0 + q.c*lim/3.0;
  802. x2 := x1 + (p.c + p.b*lim)*lim/3.0;
  803. y2 := y1 + (q.c + q.b*lim)*lim/3.0;
  804. x3 := x0 + (p.c + (p.b + p.a*lim)*lim)*lim;
  805. y3 := y0 + (q.c + (q.b + q.a*lim)*lim)*lim;
  806. xx0 := ENTIER(x0); yy0 := ENTIER(y0); xx1 := ENTIER(x1); yy1 := ENTIER(y1);
  807. xx2 := ENTIER(x2); yy2 := ENTIER(y2); xx3 := ENTIER(x3); yy3 := ENTIER(y3);
  808. Int(bodyR, xx1); Ch(bodyR, " ");
  809. Int(bodyR, yy1); Ch(bodyR, " ");
  810. Int(bodyR, xx2); Ch(bodyR, " ");
  811. Box(P, Min(xx1, xx2), Min(yy1, yy2), ABS(xx2-xx1), ABS(yy2-yy1));
  812. Int(bodyR, yy2); Ch(bodyR, " ");
  813. Int(bodyR, xx3); Ch(bodyR, " ");
  814. Box(P, Min(xx2, xx3), Min(yy2, yy3), ABS(xx3-xx2), ABS(yy3-yy2));
  815. Int(bodyR, yy3); Ch(bodyR, " ");
  816. Int(bodyR, xx0); Ch(bodyR, " ");
  817. Int(bodyR, yy0); Str(bodyR, " z");
  818. Box(P, Min(xx3, xx0), Min(yy3, yy0), ABS(xx0-xx3), ABS(yy0-yy3));
  819. Ln(bodyR);
  820. END PrintPoly;
  821. PROCEDURE Spline*(P: Printer.Printer; x0, y0, n, open: INTEGER; VAR X, Y: ARRAY OF INTEGER);
  822. VAR i: INTEGER; dx, dy, ds: REAL;
  823. x, xd, y, yd, s: RealVector;
  824. p, q: PolyVector;
  825. BEGIN
  826. WITH P: PSPrinter DO
  827. (* Don't make more that one page when making eps *)
  828. IF P.eps & (P.pno > 1) THEN RETURN END;
  829. SetColor;
  830. (*from u, v compute x, y, s*)
  831. x[0] := X[0] + x0; y[0] := Y[0] + y0; s[0] := 0; i := 1;
  832. WHILE i < n DO
  833. x[i] := X[i] + x0; dx := x[i] - x[i-1];
  834. y[i] := Y[i] + y0; dy := y[i] - y[i-1];
  835. s[i] := ABS(dx) + ABS(dy) + s[i-1]; INC(i)
  836. END ;
  837. IF open = 1 THEN OpenSpline(s, x, xd, n); OpenSpline(s, y, yd, n)
  838. ELSE ClosedSpline(s, x, xd, n); ClosedSpline(s, y, yd, n)
  839. END ;
  840. (*compute coefficients from x, y, xd, yd, s*) i := 0;
  841. WHILE i < n-1 DO
  842. ds := 1.0/(s[i+1] - s[i]);
  843. dx := (x[i+1] - x[i])*ds;
  844. p[i].a := ds*ds*(xd[i] + xd[i+1] - 2.0*dx);
  845. p[i].b := ds*(3.0*dx - 2.0*xd[i] -xd[i+1]);
  846. p[i].c := xd[i];
  847. p[i].d := x[i];
  848. p[i].t := s[i];
  849. dy := ds*(y[i+1] - y[i]);
  850. q[i].a := ds*ds*(yd[i] + yd[i+1] - 2.0*dy);
  851. q[i].b := ds*(3.0*dy - 2.0*yd[i] - yd[i+1]);
  852. q[i].c := yd[i];
  853. q[i].d := y[i];
  854. q[i].t := s[i]; INC(i)
  855. END ;
  856. p[i].t := s[i]; q[i].t := s[i];
  857. (*print polynomials*)
  858. i := 0;
  859. WHILE i < n-1 DO PrintPoly(P, p[i], q[i], p[i+1].t - p[i].t); INC(i) END
  860. END
  861. END Spline;
  862. PROCEDURE Page*(P: Printer.Printer; nofcopies: INTEGER);
  863. VAR x, y: LONGINT;
  864. BEGIN
  865. WITH P: PSPrinter DO
  866. ResetColor;
  867. CASE P.mode OF
  868. oneup, rotated:
  869. IF ~P.eps THEN
  870. Int(bodyR, nofcopies); Str(bodyR, " p"); Ln(bodyR)
  871. END;
  872. curFont := -1; INC(P.pno); ppos := Files.Pos(bodyR);
  873. Str(bodyR, "%%Page: 0 "); Int(bodyR, P.pno); Ln(bodyR);
  874. |twoup:
  875. x := 2336 * 3048 DIV P.Unit;
  876. CASE P.location OF
  877. | 0: Int(bodyR, x); Str(bodyR, " 0 translate"); Ln(bodyR)
  878. | 1: Int(bodyR, -x); Str(bodyR, " 0 translate"); Ln(bodyR);
  879. Int(bodyR, nofcopies); Str(bodyR, " p"); Ln(bodyR);
  880. curFont := -1; INC(P.pno); ppos := Files.Pos(bodyR);
  881. Str(bodyR, "%%Page: 0 "); Int(bodyR, P.pno); Ln(bodyR)
  882. END; (* CASE *)
  883. P.location := 1-P.location
  884. |fourup:
  885. x := 2336 * 3048 DIV P.Unit; y := 3520 * 3048 DIV P.Unit;
  886. CASE P.location OF
  887. | 0: Int(bodyR, x); Str(bodyR, " 0 translate"); Ln(bodyR)
  888. | 1: Int(bodyR, -x); Ch(bodyR, " "); Int(bodyR, -y); Str(bodyR, " translate"); Ln(bodyR)
  889. | 2: Int(bodyR, x); Str(bodyR, " 0 translate"); Ln(bodyR)
  890. | 3: Int(bodyR, -x); Ch(bodyR, " "); Int(bodyR, y); Str(bodyR, " translate"); Ln(bodyR);
  891. Int(bodyR, nofcopies); Str(bodyR, " p"); Ln(bodyR);
  892. curFont := -1; INC(P.pno); ppos := Files.Pos(bodyR);
  893. Str(bodyR, "%%Page: 0 "); Int(bodyR, P.pno); Ln(bodyR)
  894. END; (* CASE *)
  895. P.location := (P.location+1) MOD 4
  896. END (* CASE *)
  897. END
  898. END Page;
  899. PROCEDURE Close*(P: Printer.Printer);
  900. CONST bufSize = 4*1024;
  901. VAR
  902. dpi: LONGINT;
  903. i: INTEGER;
  904. printR, srcR: Files.Rider; buffer: ARRAY bufSize OF CHAR;
  905. S: Texts.Scanner;
  906. R: Texts.Reader; ch: CHAR;
  907. fontDef: FontDef;
  908. alias: ARRAY 64 OF CHAR;
  909. BEGIN
  910. WITH P: PSPrinter DO
  911. dpi := 914400 DIV Printer.current.Unit;
  912. IF (P.mode # oneup) & (P.location # 0) THEN
  913. Int(bodyR, 1); Str(bodyR, " p"); Ln(bodyR);
  914. curFont := -1; INC(P.pno); ppos := Files.Pos(bodyR)
  915. END;
  916. Files.Set(bodyR, bodyF, ppos); (*overwrite last %%Page line*)
  917. Str(bodyR, "%%Trailer "); Ln(bodyR);
  918. Str(bodyR, "restore"); Ln(bodyR); (* page save *)
  919. Str(bodyR, "restore"); Ln(bodyR); (* header file save *)
  920. Files.Set(printR, P.printF, 0);
  921. IF P.eps & (P.l <= P.r) & (P.b <= P.t) THEN
  922. Str(printR, "%!PS-Adobe-1.0"); Ln(printR);
  923. Str(printR, "%%BoundingBox: ");
  924. Int(printR, 0); Ch(printR, " "); Int(printR, 0); Ch(printR, " ");
  925. Int(printR, (P.r - P.l + 1)* 72 DIV (914400 DIV P.Unit)); Ch(printR, " "); Int(printR, (P.t - P.b + 1) * 72 DIV (914400 DIV P.Unit)); Ch(printR, " ");
  926. Ln(printR);
  927. Str(printR, "%%Creator: ETH Oberon"); Ln(printR);
  928. Str(printR, "%%EndComments"); Ln(printR);
  929. END;
  930. Texts.OpenReader(R, headerT, 0);
  931. Texts.Read(R, ch);
  932. WHILE ~R.eot DO
  933. Files.Write(printR, ch);
  934. IF ch = 0DX THEN Files.Write(printR, 0AX) END;
  935. Texts.Read(R, ch)
  936. END;
  937. IF P.duplex THEN
  938. Str(printR, "statusdict /setduplexmode known {statusdict begin true setduplexmode end} if");
  939. Ln(printR); Ln(printR)
  940. END;
  941. Str(printR, "/factor1 ");
  942. Real(printR, P.Unit/12700.0);
  943. Str(printR, " def"); Ln(printR);
  944. Str(printR, "/factor2 ");
  945. Real(printR, P.Unit/12700.0);
  946. Str(printR, " def"); Ln(printR); Ln(printR);
  947. i := 0;
  948. WHILE i <= fontIndex DO DefineFont(printR, fontTable[i], FALSE); INC(i) END;
  949. IF fontMapDictN > 0 THEN
  950. Str(printR, "/FontMapDict "); Int(printR, fontMapDictN); Str(printR, " dict def"); Ln(printR);
  951. Str(printR, "FontMapDict begin"); Ln(printR);
  952. fontDef := fontMapDict;
  953. WHILE fontDef # NIL DO
  954. Ch(printR, "/"); Str(printR, fontDef.name); Str(printR, " [/");
  955. IF (fontDef.family = "Syntax") OR (fontDef.family = "Oberon") OR (fontDef.family = "Default") THEN
  956. Str(printR, "Helvetica");
  957. CASE fontDef.attr OF
  958. "I": Str(printR, "-Oblique")
  959. |"M", "B": Str(printR, "-Bold")
  960. ELSE
  961. END;
  962. Ch(printR, " ");
  963. Int(printR, fontDef.size*(4*dpi) DIV 300)
  964. (*Int(printR, (fontDef.size*11+2)*dpi DIV 100)*)
  965. ELSIF (fontDef.family = "Helvetica") OR (fontDef.family = "Courier") THEN
  966. Str(printR, fontDef.family);
  967. CASE fontDef.attr OF
  968. "I": Str(printR, "-Oblique")
  969. |"M", "B": Str(printR, "-Bold")
  970. ELSE
  971. END;
  972. Ch(printR, " ");
  973. Int(printR, fontDef.size*(4*dpi) DIV 300)
  974. ELSIF fontDef.family = "Times" THEN
  975. Str(printR, "Times");
  976. CASE fontDef.attr OF
  977. "I": Str(printR, "-Italic")
  978. |"M", "B": Str(printR, "-Bold")
  979. ELSE
  980. Str(printR, "-Roman")
  981. END;
  982. Ch(printR, " ");
  983. Int(printR, fontDef.size*(4*dpi) DIV 300)
  984. ELSE
  985. buffer := "Printer.PSPrinter."; Strings.Append(buffer, fontDef.family);
  986. Oberon.OpenScanner (S, buffer);
  987. IF S.class IN {Texts.Name, Texts.String} THEN
  988. COPY(S.s, alias); Str(printR, alias)
  989. ELSE
  990. Str(printR, fontDef.family)
  991. END;
  992. CASE fontDef.attr OF
  993. "I": Str(printR, "-Italic")
  994. |"M", "B": Str(printR, "-Bold")
  995. ELSE
  996. END;
  997. Ch(printR, " ");
  998. Int(printR, fontDef.size*(4*dpi) DIV 300)
  999. END;
  1000. Str(printR, "] def"); Ln(printR);
  1001. fontDef := fontDef.next
  1002. END;
  1003. Str(printR, "end"); Ln(printR);
  1004. fontMapDict := NIL; fontMapDictN := 0
  1005. END;
  1006. Ln(printR);
  1007. i := 0;
  1008. WHILE i <= fontIndex DO DefineFont(printR, fontTable[i], TRUE); INC(i) END;
  1009. Ln(printR);
  1010. Str(printR, "OberonInit"); Ln(printR); Ln(printR);
  1011. CASE P.mode OF
  1012. oneup:
  1013. (* skip *)
  1014. |twoup:
  1015. Str(printR, "90 rotate"); Ln(printR);
  1016. Str(printR, "0.7071 0.7071 scale"); Ln(printR);
  1017. Str(printR, "0 "); Int(printR, -3520 * 3048 DIV P.Unit); Str(printR, " translate"); Ln(printR)
  1018. |fourup:
  1019. Str(printR, "0.5 0.5 scale"); Ln(printR);
  1020. Str(printR, "0 "); Int(printR, 3520 * 3048 DIV P.Unit); Str(printR, " translate"); Ln(printR)
  1021. |rotated:
  1022. Str(printR, "90 rotate"); Ln(printR);
  1023. Str(printR, "0 "); Int(printR, -2489 * 3048 DIV P.Unit); Str(printR, " translate"); Ln(printR)
  1024. END;
  1025. Str(printR, "save"); Ln(printR); Ln(printR);
  1026. Str(printR, "%%EndProlog"); Ln(printR);
  1027. Str(printR, "%%Page: 0 1"); Ln(printR);
  1028. Ln(printR);
  1029. IF P.eps THEN
  1030. Int(printR, -P.l); Ch(printR, " "); Int(printR, -P.b);
  1031. Str(printR, " translate"); Ln(printR);
  1032. END;
  1033. Files.Set(srcR, bodyF, 0);
  1034. REPEAT Files.ReadBytes(srcR, buffer, bufSize); Files.WriteBytes(printR, buffer, bufSize-srcR.res) UNTIL srcR.eof;
  1035. IF ~P.anonymous THEN Files.Register(P.printF) END;
  1036. P.res := Printer.res;
  1037. Files.Set(bodyR, NIL, 0);
  1038. headerT := NIL; bodyF := NIL
  1039. END
  1040. END Close;
  1041. PROCEDURE GetMetric* (P: Printer.Printer; fnt: Fonts.Font): Fonts.Font;
  1042. VAR name: ARRAY 32 OF CHAR; i: INTEGER; metric: Fonts.Font;
  1043. BEGIN
  1044. COPY(fnt.name, name);
  1045. i := 0; WHILE (name[i] # ".") & (name[i] # 0X) DO INC(i) END;
  1046. (* look for Mdx *)
  1047. name[i] := "."; name[i+1] := "M"; name[i+2] := "d";
  1048. name[i+3] := CHR(30H + 914400 DIV (100 * P.Unit));
  1049. name[i+4] := "."; name[i+5] := "F"; name[i+6] := "n"; name[i+7] := "t";
  1050. name[i+8] := 0X;
  1051. metric := Fonts.This(name);
  1052. IF metric.type = Fonts.substitute THEN metric := NIL END;
  1053. RETURN metric
  1054. END GetMetric;
  1055. PROCEDURE NewPrinter*(): Printer.Printer;
  1056. VAR P: PSPrinter;
  1057. BEGIN
  1058. NEW(P);
  1059. P.gen := "PSPrinter.Install";
  1060. P.InitMetrics := InitMetrics;
  1061. P.Escape := Escape;
  1062. P.Open := Open;
  1063. P.Close := Close;
  1064. P.Page := Page;
  1065. P.ReplConst := ReplConst;
  1066. P.ReplPattern := ReplPattern;
  1067. P.Line := Line;
  1068. P.Circle := Circle;
  1069. P.Ellipse := Ellipse;
  1070. P.Spline := Spline;
  1071. P.Picture := Picture;
  1072. P.UseListFont := UseListFont;
  1073. P.String := String;
  1074. P.ContString := ContString;
  1075. P.UseColor := UseColor;
  1076. P.GetMetric := GetMetric;
  1077. RETURN P
  1078. END NewPrinter;
  1079. PROCEDURE Install*;
  1080. BEGIN
  1081. Printer.Install(NewPrinter());
  1082. END Install;
  1083. PROCEDURE Init;
  1084. VAR class: Objects.Name; size: LONGINT; style: SET;
  1085. BEGIN
  1086. ParseName(Fonts.Default.name, default, size, style, class)
  1087. END Init;
  1088. PROCEDURE Cleanup;
  1089. BEGIN
  1090. IF (Printer.current # NIL) & (Printer.current IS PSPrinter) THEN
  1091. Printer.current := NIL
  1092. END
  1093. END Cleanup;
  1094. BEGIN
  1095. hexArray := "0123456789ABCDEF";
  1096. metric := NIL; Init();
  1097. Modules.InstallTermHandler(Cleanup)
  1098. END PSPrinter.