bdftops.ps 23 KB

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