bdftops.ps 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797
  1. % Copyright (C) 1990, 1995, 1996 Aladdin Enterprises. All rights reserved.
  2. %
  3. % This file is part of AFPL Ghostscript.
  4. %
  5. % AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author or
  6. % distributor accepts any responsibility for the consequences of using it, or
  7. % for whether it serves any particular purpose or works at all, unless he or
  8. % she says so in writing. Refer to the Aladdin Free Public License (the
  9. % "License") for full details.
  10. %
  11. % Every copy of AFPL Ghostscript must include a copy of the License, normally
  12. % in a plain ASCII text file named PUBLIC. The License grants you the right
  13. % to copy, modify and redistribute AFPL Ghostscript, but only under certain
  14. % conditions described in the License. Among other things, the License
  15. % requires that the copyright notice and this notice be preserved on all
  16. % copies.
  17. % $Id: bdftops.ps,v 1.3 2001/03/27 20:53:36 alexcher Exp $
  18. % bdftops.ps
  19. % Convert a BDF file (possibly with (an) associated AFM file(s))
  20. % to a PostScript Type 1 font (without eexec encryption).
  21. % The resulting font will work with any PostScript language interpreter,
  22. % but not with ATM or other font rasterizers lacking a complete interpreter.
  23. /envBDF 120 dict def
  24. envBDF begin
  25. % "Import" the image-to-path package.
  26. % This also brings in the Type 1 opcodes (type1ops.ps).
  27. (impath.ps) runlibfile
  28. % "Import" the font-writing package.
  29. (wrfont.ps) runlibfile
  30. wrfont_dict begin
  31. /binary_CharStrings false def
  32. /binary_tokens false def
  33. /encrypt_CharStrings true def
  34. /standard_only true def
  35. end
  36. /lenIV 0 def
  37. % Invert the StandardEncoding vector.
  38. 256 dict dup begin
  39. 0 1 255 { dup StandardEncoding exch get exch def } for
  40. end /StandardDecoding exch def
  41. % Define the properties copied to FontInfo.
  42. mark
  43. (COPYRIGHT) /Notice
  44. (FAMILY_NAME) /FamilyName
  45. (FULL_NAME) /FullName
  46. (WEIGHT_NAME) /Weight
  47. .dicttomark /properties exch def
  48. % Define the character sequences for synthesizing missing composite
  49. % characters in the standard encoding.
  50. mark
  51. /AE [/A /E]
  52. /OE [/O /E]
  53. /ae [/a /e]
  54. /ellipsis [/period /period /period]
  55. /emdash [/hyphen /hyphen /hyphen]
  56. /endash [/hyphen /hyphen]
  57. /fi [/f /i]
  58. /fl [/f /l]
  59. /germandbls [/s /s]
  60. /guillemotleft [/less /less]
  61. /guillemotright [/greater /greater]
  62. /oe [/o /e]
  63. /quotedblbase [/comma /comma]
  64. .dicttomark /composites exch def
  65. % Define the procedure for synthesizing composites.
  66. % This must not be bound.
  67. /compose
  68. { exch pop
  69. FontMatrix Private /composematrix get invertmatrix concat
  70. 0 0 moveto
  71. dup gsave false charpath pathbbox currentpoint grestore
  72. 6 2 roll setcachedevice show
  73. } def
  74. % Define the CharString procedure that calls compose, with the string
  75. % on the stack. This too must remain unbound.
  76. /compose_proc
  77. { Private /compose get exec
  78. } def
  79. % Define aliases for missing characters similarly.
  80. mark
  81. /acute /quoteright
  82. /bullet /asterisk
  83. /cedilla /comma
  84. /circumflex /asciicircum
  85. /dieresis /quotedbl
  86. /dotlessi /i
  87. /exclamdown /exclam
  88. /florin /f
  89. /fraction /slash
  90. /grave /quoteleft
  91. /guilsinglleft /less
  92. /guilsinglright /greater
  93. /hungarumlaut /quotedbl
  94. /periodcentered /asterisk
  95. /questiondown /question
  96. /quotedblleft /quotedbl
  97. /quotedblright /quotedbl
  98. /quotesinglbase /comma
  99. /quotesingle /quoteright
  100. /tilde /asciitilde
  101. .dicttomark /aliases exch def
  102. % Define overstruck characters that can be synthesized with seac.
  103. mark
  104. [ /Aacute /Acircumflex /Adieresis /Agrave /Aring /Atilde
  105. /Ccedilla
  106. /Eacute /Ecircumflex /Edieresis /Egrave
  107. /Iacute /Icircumflex /Idieresis /Igrave
  108. /Lslash
  109. /Ntilde
  110. /Oacute /Ocircumflex /Odieresis /Ograve /Otilde
  111. /Scaron
  112. /Uacute /Ucircumflex /Udieresis /Ugrave
  113. /Yacute /Ydieresis
  114. /Zcaron
  115. /aacute /acircumflex /adieresis /agrave /aring /atilde
  116. /ccedilla
  117. /eacute /ecircumflex /edieresis /egrave
  118. /iacute /icircumflex /idieresis /igrave
  119. /lslash
  120. /ntilde
  121. /oacute /ocircumflex /odieresis /ograve /otilde
  122. /scaron
  123. /uacute /ucircumflex /udieresis /ugrave
  124. /yacute /ydieresis
  125. /zcaron
  126. ]
  127. { dup =string cvs
  128. [ exch dup 0 1 getinterval cvn
  129. exch dup length 1 sub 1 exch getinterval cvn
  130. ]
  131. } forall
  132. /cent [/c /slash]
  133. /daggerdbl [/bar /equal]
  134. /divide [/colon /hyphen]
  135. /sterling [/L /hyphen]
  136. /yen [/Y /equal]
  137. .dicttomark /accentedchars exch def
  138. % ------ Output utilities ------ %
  139. /ws {psfile exch writestring} bind def
  140. /wl {ws (\n) ws} bind def
  141. /wt {=string cvs ws ( ) ws} bind def
  142. % ------ BDF file parsing utilities ------ %
  143. % Define a buffer for reading the BDF file.
  144. /buffer 400 string def
  145. % Read a line from the BDF file into the buffer.
  146. % Ignore empty (zero-length) lines.
  147. % Define /keyword as the first word on the line.
  148. % Define /args as the remainder of the line.
  149. % If the keyword is equal to commentword, skip the line.
  150. % (If commentword is equal to a space, never skip.)
  151. /nextline
  152. { { bdfile buffer readline not
  153. { (Premature EOF\n) print stop } if
  154. dup length 0 ne { exit } if pop
  155. }
  156. loop
  157. ( ) search
  158. { /keyword exch def pop }
  159. { /keyword exch def () }
  160. ifelse
  161. /args exch def
  162. keyword commentword eq { nextline } if
  163. } bind def
  164. % Get a word argument from args. We do *not* copy the string.
  165. /warg % warg -> string
  166. { args ( ) search
  167. { exch pop exch }
  168. { () }
  169. ifelse /args exch def
  170. } bind def
  171. % Get an integer argument from args.
  172. /iarg % iarg -> int
  173. { warg cvi
  174. } bind def
  175. % Get a numeric argument from args.
  176. /narg % narg -> int|real
  177. { warg cvr
  178. dup dup cvi eq { cvi } if
  179. } bind def
  180. % Convert the remainder of args into a string.
  181. /remarg % remarg -> string
  182. { args copystring
  183. } bind def
  184. % Get a string argument that occupies the remainder of args.
  185. /sarg % sarg -> string
  186. { args (") anchorsearch
  187. { pop /args exch def } { pop } ifelse
  188. args args length 1 sub get (") 0 get eq
  189. { args 0 args length 1 sub getinterval /args exch def } if
  190. args copystring
  191. } bind def
  192. % Check that the keyword is the expected one.
  193. /checkline % (EXPECTED-KEYWORD) checkline ->
  194. { dup keyword ne
  195. { (Expected ) print =
  196. (Line=) print keyword print ( ) print args print (\n) print stop
  197. } if
  198. pop
  199. } bind def
  200. % Read a line and check its keyword.
  201. /getline % (EXPECTED-KEYWORD) getline ->
  202. { nextline checkline
  203. } bind def
  204. % Find the first/last non-zero bit of a non-zero byte.
  205. /fnzb
  206. { 0 { exch dup 128 ge { pop exit } { dup add exch 1 add } ifelse }
  207. loop
  208. } bind def
  209. /lnzb
  210. { 7 { exch dup 1 and 0 ne { pop exit } { -1 bitshift exch 1 sub } ifelse }
  211. loop
  212. } bind def
  213. % ------ Type 1 encoding utilities ------ %
  214. % Parse the side bearing and width information that begins a CharString.
  215. % Arguments: charstring. Result: sbx sby wx wy substring.
  216. /parsesbw
  217. { mark exch lenIV
  218. { % stack: mark ... string dropcount
  219. dup 2 index length exch sub getinterval
  220. dup 0 get dup 32 lt { pop exit } if
  221. dup 246 le
  222. { 139 sub exch 1 }
  223. { dup 250 le
  224. { 247 sub 8 bitshift 108 add 1 index 1 get add exch 2 }
  225. { dup 254 le
  226. { 251 sub 8 bitshift 108 add 1 index 1 get add neg exch 2 }
  227. { pop dup 1 get 128 xor 128 sub
  228. 8 bitshift 1 index 2 get add
  229. 8 bitshift 1 index 3 get add
  230. 8 bitshift 1 index 4 get add exch 5
  231. } ifelse
  232. } ifelse
  233. } ifelse
  234. } loop
  235. counttomark 3 eq { 0 3 1 roll 0 exch } if
  236. 6 -1 roll pop
  237. } bind def
  238. % Find the side bearing and width information that begins a CharString.
  239. % Arguments: charstring. Result: charstring sizethroughsbw.
  240. /findsbw
  241. { dup parsesbw 4 { exch pop } repeat skipsbw
  242. } bind def
  243. /skipsbw % charstring sbwprefix -> sizethroughsbw
  244. { length 1 index length exch sub
  245. 2 copy get 12 eq { 2 } { 1 } ifelse add
  246. } bind def
  247. % Encode a number, and append it to a string.
  248. % Arguments: str num. Result: newstr.
  249. /concatnum
  250. { dup dup -107 ge exch 107 le and
  251. { 139 add 1 string dup 0 3 index put }
  252. { dup dup -1131 ge exch 1131 le and
  253. { dup 0 ge { 16#f694 } { neg 16#fa94 } ifelse add
  254. 2 string dup 0 3 index -8 bitshift put
  255. dup 1 3 index 255 and put
  256. }
  257. { 5 string dup 0 255 put exch
  258. 2 copy 1 exch -24 bitshift 255 and put
  259. 2 copy 2 exch -16 bitshift 255 and put
  260. 2 copy 3 exch -8 bitshift 255 and put
  261. 2 copy 4 exch 255 and put
  262. exch
  263. }
  264. ifelse
  265. }
  266. ifelse exch pop concatstrings
  267. } bind def
  268. % ------ Point arithmetic utilities ------ %
  269. /ptadd { exch 4 -1 roll add 3 1 roll add } bind def
  270. /ptexch { 4 2 roll } bind def
  271. /ptneg { neg exch neg exch } bind def
  272. /ptpop { pop pop } bind def
  273. /ptsub { ptneg ptadd } bind def
  274. % ------ The main program ------ %
  275. /readBDF % <infilename> <outfilename> <fontname>
  276. % <encodingname> <uniqueID> <xuid> readBDF -> <font>
  277. { /xuid exch def % may be null
  278. /uniqueID exch def % may be -1
  279. /encodingname exch def
  280. /encoding encodingname cvx exec def
  281. /fontname exch def
  282. /psname exch def
  283. /bdfname exch def
  284. gsave % so we can set the CTM to the font matrix
  285. % Open the input files. We don't open the output file until
  286. % we've done a minimal validity check on the input.
  287. bdfname (r) file /bdfile exch def
  288. /commentword ( ) def
  289. % Check for the STARTFONT.
  290. (STARTFONT) getline
  291. args (2.1) ne { (Not version 2.1\n) print stop } if
  292. % Initialize the font.
  293. /Font 20 dict def
  294. Font begin
  295. /FontName fontname def
  296. /PaintType 0 def
  297. /FontType 1 def
  298. uniqueID 0 gt { /UniqueID uniqueID def } if
  299. xuid null ne { /XUID xuid def } if
  300. /Encoding encoding def
  301. /FontInfo 20 dict def
  302. /Private 20 dict def
  303. currentdict end currentdict end
  304. exch begin begin % insert font above environment
  305. % Initialize the Private dictionary in the font.
  306. Private begin
  307. /-! {string currentfile exch readhexstring pop} readonly def
  308. /-| {string currentfile exch readstring pop} readonly def
  309. /|- {readonly def} readonly def
  310. /| {readonly put} readonly def
  311. /BlueValues [] def
  312. /lenIV lenIV def
  313. /MinFeature {16 16} def
  314. /password 5839 def
  315. /UniqueID uniqueID def
  316. end % Private
  317. % Invert the Encoding, for synthesizing composite characters.
  318. /decoding encoding length dict def
  319. 0 1 encoding length 1 sub
  320. { dup encoding exch get exch decoding 3 1 roll put }
  321. for
  322. % Now open the output file.
  323. psname (w) file /psfile exch def
  324. % Put out a header compatible with the Adobe "standard".
  325. (%!FontType1-1.0: ) ws fontname wt (000.000) wl
  326. (% This is a font description converted from ) ws
  327. bdfname wl
  328. (% by bdftops running on ) ws
  329. statusdict /product get ws ( revision ) ws
  330. revision =string cvs ws (.) wl
  331. % Copy the initial comments, up to FONT.
  332. true
  333. { nextline
  334. keyword (COMMENT) ne {exit} if
  335. { (% Here are the initial comments from the BDF file:\n%) wl
  336. } if false
  337. (%) ws remarg wl
  338. } loop pop
  339. () wl
  340. /commentword (COMMENT) def % do skip comments from now on
  341. % Read and process the FONT, SIZE, and FONTBOUNDINGBOX.
  342. % If we cared about FONT, we'd use it here. If the BDF files
  343. % from MIT had PostScript names rather than X names, we would
  344. % care; but what's there is unusable, so we discard FONT.
  345. % The FONTBOUNDINGBOX may not be reliable, so we discard it too.
  346. (FONT) checkline
  347. (SIZE) getline
  348. /pointsize iarg def /xres iarg def /yres iarg def
  349. (FONTBOUNDINGBOX) getline
  350. nextline
  351. % Initialize the font bounding box bookeeping.
  352. /fbbxo 1000 def
  353. /fbbyo 1000 def
  354. /fbbxe -1000 def
  355. /fbbye -1000 def
  356. % Read and process the properties. We only care about a few of them.
  357. keyword (STARTPROPERTIES) eq
  358. { iarg
  359. { nextline
  360. properties keyword known
  361. { FontInfo properties keyword get sarg readonly put
  362. } if
  363. } repeat
  364. (ENDPROPERTIES) getline
  365. nextline
  366. } if
  367. % Compute and set the FontMatrix.
  368. Font /FontMatrix
  369. [ 0.001 0 0 0.001 xres mul yres div 0 0 ] readonly
  370. dup setmatrix put
  371. % Read and process the header for the bitmaps.
  372. (CHARS) checkline
  373. /ccount iarg def
  374. % Initialize the CharStrings dictionary.
  375. /charstrings ccount
  376. composites length add
  377. aliases length add
  378. accentedchars length add
  379. 1 add dict def % 1 add for .notdef
  380. /isfixedwidth true def
  381. /fixedwidth null def
  382. /subrcount 0 def
  383. /subrs [] def
  384. % Read the bitmap data. This reads the remainder of the file.
  385. % We do this before processing the bitmaps so that we can compute
  386. % the correct FontBBox first.
  387. /chardata ccount dict def
  388. ccount -1 1
  389. { (STARTCHAR) getline
  390. /charname remarg def
  391. (ENCODING) getline
  392. /eindex iarg def
  393. eindex dup 0 ge exch 255 le and
  394. { charname /charname StandardEncoding eindex get def
  395. charname /.notdef eq eindex 0 gt and
  396. { /charname (A) eindex =string cvs concatstrings cvn def
  397. }
  398. if
  399. (/) print charname =string cvs print (,) print print
  400. }
  401. { (/) print charname print
  402. }
  403. ifelse
  404. 10 mod 1 eq { (\n) print flush } if
  405. (SWIDTH) getline
  406. /swx iarg pointsize mul 1000 div xres mul 72 div def
  407. /swy iarg pointsize mul 1000 div xres mul 72 div def
  408. (DWIDTH) getline % Ignore, use SWIDTH instead
  409. (BBX) getline
  410. /bbw iarg def /bbh iarg def /bbox iarg def /bboy iarg def
  411. nextline
  412. keyword (ATTRIBUTES) eq
  413. { nextline
  414. } if
  415. (BITMAP) checkline
  416. % Update the font bounding box.
  417. /fbbxo fbbxo bbox min def
  418. /fbbyo fbbyo bboy min def
  419. /fbbxe fbbxe bbox bbw add max def
  420. /fbbye fbbye bboy bbh add max def
  421. % Read the bits for this character.
  422. /raster bbw 7 add 8 idiv def
  423. /cbits raster bbh mul string def
  424. cbits length 0 gt
  425. { 0 raster cbits length raster sub
  426. { cbits exch raster getinterval
  427. bdfile buffer readline not
  428. { (EOF in bitmap\n) print stop } if
  429. % stack has <cbits.interval> <buffer.interval>
  430. 0 () /SubFileDecode filter
  431. exch 2 copy readhexstring pop pop pop closefile
  432. } for
  433. } if
  434. (ENDCHAR) getline
  435. % Save the character data.
  436. chardata charname [swx swy bbw bbh bbox bboy cbits] put
  437. } for
  438. (ENDFONT) getline
  439. % Allocate the buffers for the bitmap and the outline,
  440. % according to the font bounding box.
  441. /fbbw fbbxe fbbxo sub def
  442. /fbbh fbbye fbbyo sub def
  443. /fraster fbbw 7 add 8 idiv def
  444. /bits fraster fbbh mul 200 max 65535 min string def
  445. /outline bits length 6 mul 65535 min string def
  446. % Process the characters.
  447. chardata
  448. { exch /charname exch def aload pop
  449. /cbits exch def
  450. /bboy exch def /bbox exch def
  451. /bbh exch def /bbw exch def
  452. /swy exch def /swx exch def
  453. % The bitmap handed to type1imagepath must have the correct height,
  454. % because type1imagepath uses this to compute the scale factor,
  455. % so we have to clear the unused parts of it.
  456. /raster bbw 7 add 8 idiv def
  457. bits dup 0 1 raster fbbh mul 1 sub
  458. { 0 put dup } for
  459. pop pop
  460. bits raster fbbh bbh sub mul cbits putinterval
  461. % Compute the font entry, converting the bitmap to an outline.
  462. bits 0 raster fbbh mul getinterval % the bitmap image
  463. bbw fbbh % bitmap width & height
  464. swx swy % width x & y
  465. bbox neg bboy neg % origin x & y
  466. % Account for lenIV when converting the outline.
  467. outline lenIV outline length lenIV sub getinterval
  468. type1imagepath
  469. length lenIV add
  470. outline exch 0 exch getinterval
  471. % Check for a fixed width font.
  472. isfixedwidth
  473. { fixedwidth null eq
  474. { /fixedwidth swx def }
  475. { fixedwidth swx ne { /isfixedwidth false def } if }
  476. ifelse
  477. } if
  478. % Finish up the character.
  479. copystring
  480. charname exch charstrings 3 1 roll put
  481. } forall
  482. % Add CharStrings entries for aliases.
  483. aliases
  484. { charstrings 2 index known not charstrings 2 index known and
  485. { charstrings exch get charstrings 3 1 roll put
  486. }
  487. { pop pop
  488. }
  489. ifelse
  490. }
  491. forall
  492. % If this is not a fixed-width font, synthesize missing characters
  493. % out of available ones.
  494. isfixedwidth not
  495. { false composites
  496. { 1 index charstrings exch known not
  497. 1 index { decoding exch known and } forall
  498. { ( /) print 1 index bits cvs print
  499. /combine exch def
  500. 0 1 combine length 1 sub
  501. { dup combine exch get decoding exch get
  502. bits 3 1 roll put
  503. } for
  504. bits 0 combine length getinterval copystring
  505. [ exch /compose_proc load aload pop ] cvx
  506. charstrings 3 1 roll put
  507. pop true
  508. }
  509. { pop pop }
  510. ifelse
  511. }
  512. forall flush
  513. { Private /composematrix matrix put
  514. Private /compose /compose load put
  515. }
  516. if
  517. }
  518. if
  519. % Synthesize accented characters with seac if needed and possible.
  520. accentedchars
  521. { aload pop /accent exch def /base exch def
  522. buffer cvs /accented exch def
  523. charstrings accented known not
  524. charstrings base known and
  525. charstrings accent known and
  526. StandardDecoding base known and
  527. StandardDecoding accent known and
  528. encoding StandardDecoding base get get base eq and
  529. encoding StandardDecoding accent get get accent eq and
  530. { ( /) print accented print
  531. charstrings base get findsbw 0 exch getinterval
  532. /acstring exch def % start with sbw of base
  533. charstrings accent get parsesbw
  534. 4 { pop } repeat % just leave sbx
  535. acstring exch concatnum
  536. 0 concatnum 0 concatnum % adx ady
  537. decoding base get concatnum % bchar
  538. decoding accent get concatnum % achar
  539. s_seac concatstrings
  540. charstrings exch accented copystring exch put
  541. } if
  542. } forall
  543. % Make a CharStrings entry for .notdef.
  544. outline lenIV <8b8b0d0e> putinterval % 0 0 hsbw endchar
  545. charstrings /.notdef outline 0 lenIV 4 add getinterval copystring put
  546. % Encrypt the CharStrings and Subrs (in place).
  547. charstrings
  548. { % Be careful not to encrypt aliased characters twice,
  549. % since they share their CharString.
  550. aliases 2 index known
  551. { charstrings aliases 3 index get .knownget
  552. { 1 index ne }
  553. { true }
  554. ifelse
  555. }
  556. { true
  557. }
  558. ifelse
  559. 1 index type /stringtype eq and
  560. { 4330 exch dup .type1encrypt exch pop
  561. readonly charstrings 3 1 roll put
  562. }
  563. { pop pop
  564. }
  565. ifelse
  566. }
  567. forall
  568. 0 1 subrcount 1 sub
  569. { dup subrs exch get
  570. 4330 exch dup .type1encrypt exch pop
  571. subrs 3 1 roll put
  572. }
  573. for
  574. % Make most of the remaining entries in the font dictionaries.
  575. % The Type 1 font machinery really only works with a 1000 unit
  576. % character coordinate system. Set this up here, by computing the factor
  577. % to make the X entry in the FontMatrix come out at exactly 0.001.
  578. /fontscale 1000 fbbh div yres mul xres div def
  579. Font /FontBBox
  580. [ fbbxo fontscale mul
  581. fbbyo fontscale mul
  582. fbbxe fontscale mul
  583. fbbye fontscale mul
  584. ] cvx readonly put
  585. Font /CharStrings charstrings readonly put
  586. FontInfo /FullName known not
  587. { % Some programs insist on FullName being present.
  588. FontInfo /FullName FontName dup length string cvs put
  589. }
  590. if
  591. FontInfo /isFixedPitch isfixedwidth put
  592. subrcount 0 gt
  593. { Private /Subrs subrs 0 subrcount getinterval readonly put
  594. } if
  595. % Determine the italic angle and underline position
  596. % by actually installing the font.
  597. save
  598. /_temp_ Font definefont setfont
  599. [1000 0 0 1000 0 0] setmatrix % mitigate rounding problems
  600. % The italic angle is the multiple of -5 degrees
  601. % that minimizes the width of the 'I'.
  602. 0 9999 0 5 85
  603. { dup rotate
  604. newpath 0 0 moveto (I) false charpath
  605. dup neg rotate
  606. pathbbox pop exch pop exch sub
  607. dup 3 index lt { 4 -2 roll } if
  608. pop pop
  609. }
  610. for pop
  611. % The underline position is halfway between the bottom of the 'A'
  612. % and the bottom of the FontBBox.
  613. newpath 0 0 moveto (A) false charpath
  614. FontMatrix concat
  615. pathbbox pop pop exch pop
  616. % Put the values in FontInfo.
  617. 3 -1 roll
  618. restore
  619. Font /FontBBox get 1 get add 2 div cvi
  620. dup FontInfo /UnderlinePosition 3 -1 roll put
  621. 2 div abs FontInfo /UnderlineThickness 3 -1 roll put
  622. FontInfo /ItalicAngle 3 -1 roll put
  623. % Clean up and finish.
  624. grestore
  625. bdfile closefile
  626. Font currentdict end end begin % remove font from dict stack
  627. (\n) print flush
  628. } bind def
  629. % ------ Reader for AFM files ------ %
  630. % Dictionary for looking up character keywords
  631. /cmdict 6 dict dup begin
  632. /C { /c iarg def } def
  633. /N { /n warg copystring def } def
  634. /WX { /w narg def } def
  635. /W0X /WX load def
  636. /W /WX load def
  637. /W0 /WX load def
  638. end def
  639. /readAFM % fontdict afmfilename readAFM -> fontdict
  640. { (r) file /bdfile exch def
  641. /Font exch def
  642. /commentword (Comment) def
  643. % Check for the StartFontMetrics.
  644. (StartFontMetrics) getline
  645. args cvr 2.0 lt { (Not version 2.0 or greater\n) print stop } if
  646. % Look for StartCharMetrics, then parse the character metrics.
  647. % The only information we care about is the X width.
  648. /metrics 0 dict def
  649. { nextline
  650. keyword (EndFontMetrics) eq { exit } if
  651. keyword (StartCharMetrics) eq
  652. { iarg dup dict /metrics exch def
  653. { /c -1 def /n null def /w null def
  654. nextline buffer
  655. { token not { exit } if
  656. dup cmdict exch known
  657. { exch /args exch def cmdict exch get exec args }
  658. { pop }
  659. ifelse
  660. } loop
  661. c 0 ge n null ne or w null ne and
  662. { n null eq { /n Font /Encoding get c get def } if
  663. metrics n w put
  664. }
  665. if
  666. }
  667. repeat
  668. (EndCharMetrics) getline
  669. } if
  670. } loop
  671. % Insert the metrics in the font.
  672. metrics length 0 ne
  673. { Font /Metrics metrics readonly put
  674. } if
  675. Font
  676. } bind def
  677. end % envBDF
  678. % Enter the main program in the current dictionary.
  679. /bdfafmtops % infilename afmfilename* outfilename fontname
  680. % encodingname uniqueID xuid
  681. { envBDF begin
  682. 7 -2 roll exch 7 2 roll % afm* in out fontname encodingname uniqueID xuid
  683. readBDF % afm* font
  684. exch { readAFM } forall
  685. save exch
  686. dup /FontName get exch definefont
  687. setfont
  688. psfile writefont
  689. restore
  690. psfile closefile
  691. end
  692. } bind def
  693. % If the program was invoked from the command line, run it now.
  694. [ shellarguments
  695. { counttomark 4 ge
  696. { dup 0 get
  697. dup 48 ge exch 57 le and % last arg starts with a digit?
  698. { /StandardEncoding } % no encodingname
  699. { cvn } % have encodingname
  700. ifelse
  701. exch (.) search % next-to-last arg has . in it?
  702. { mark 4 1 roll % have xuid
  703. { cvi exch pop exch (.) search not { exit } if }
  704. loop cvi ]
  705. 3 -1 roll cvi exch
  706. }
  707. { cvi null % no xuid
  708. }
  709. ifelse
  710. counttomark 5 roll
  711. counttomark 6 sub array astore
  712. 7 -2 roll cvn 7 -3 roll % make sure fontname is a name
  713. bdfafmtops
  714. }
  715. { cleartomark
  716. (Usage:\n bdftops xx.bdf [yy1.afm ...] zz.gsf fontname uniqueID [xuid] [encodingname]\n) print flush
  717. mark
  718. }
  719. ifelse
  720. }
  721. if pop