font2pcl.ps 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. % Copyright (C) 1993, 1994, 1995, 1997 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: font2pcl.ps,v 1.5 2002/06/02 12:03:28 mpsuzuki Exp $
  16. % font2pcl.ps
  17. % Write out a font as a PCL bitmap font.
  18. /pcldict 60 dict def
  19. % Write out the current font as a PCL bitmap font.
  20. % The current transformation matrix defines the font size and orientation.
  21. /WriteResolution? false def % true=use "resolution bound font" format,
  22. % false=use older format
  23. /LJ4 false def % true=use LJ4 Typeface code
  24. % false=use LJIIP/IID/IIIx Typeface code
  25. pcldict begin % internal procedures
  26. /findstring % <string> <substring> findstring <bool>
  27. { search { pop pop pop true } { pop false } ifelse
  28. } def
  29. % Determine which set of keywords is present in a string.
  30. % The last keyword set must be empty.
  31. /keysearch % <string> <array of arrays of keywords> keysearch <index>
  32. { 0 1 2 index length 1 sub
  33. { 2 copy get true exch
  34. { % Stack: <string> <a.a.k.> <index> <bool> <keyword>
  35. 4 index exch findstring and
  36. }
  37. forall
  38. { 0 exch getinterval exit
  39. }
  40. if pop
  41. }
  42. for
  43. exch pop length % invalid index if missing
  44. } def
  45. % Determine the device height of a string in quarter-dots.
  46. /charheight % <string> charheight <int>
  47. { gsave newpath 0 0 moveto false charpath
  48. pathbbox exch pop exch sub exch pop 0 exch grestore
  49. dtransform add abs 4 mul cvi
  50. } def
  51. % Compute an integer version of the transformed FontBBox.
  52. /inflate % <num> inflate <num>
  53. { dup 0 gt { ceiling } { floor } ifelse
  54. } def
  55. /ixbbox % - ixbbox <llx> <lly> <urx> <ury>
  56. { /FontBBox load aload pop % might be executable or literal
  57. 4 2 roll transform exch truncate cvi exch truncate cvi
  58. 4 2 roll transform exch inflate cvi exch inflate cvi
  59. } def
  60. % Determine the original font of a possibly transformed font.
  61. % Since some badly behaved PostScript files construct transformed
  62. % fonts "by hand", we can't just rely on the OrigFont pointers.
  63. % Instead, if a font with the given name exists, and if its
  64. % entries for FontType and UniqueID match those of the font we
  65. % obtain by following the OrigFont chain, we use that font.
  66. /origfont
  67. { { dup /OrigFont known not { exit } if /OrigFont get } loop
  68. FontDirectory 1 index /FontName get .knownget
  69. { % Stack: origfont namedfont
  70. 1 index /FontType get 1 index /FontType get eq
  71. { 1 index /UniqueID .knownget
  72. { 1 index /UniqueID .knownget
  73. { eq { exch } if }
  74. { pop }
  75. ifelse
  76. }
  77. if
  78. }
  79. if pop
  80. }
  81. if
  82. } def
  83. % Determine the bounding box of the current device's image.
  84. % Free variables: row, zerow.
  85. /devbbox % <rw> <rh> devbbox <ymin> <ymax1> <xmin> <xmax1>
  86. { % Find top and bottom whitespace.
  87. dup
  88. { dup 0 eq { exit } if 1 sub
  89. dup currentdevice exch row copyscanlines
  90. zerow ne { 1 add exit } if
  91. }
  92. loop % ymax1
  93. 0
  94. { 2 copy eq { exit } if
  95. dup currentdevice exch row copyscanlines
  96. zerow ne { exit } if
  97. 1 add
  98. }
  99. loop % ymin
  100. exch
  101. % Find left and right whitespace.
  102. 3 index 0
  103. % Stack: rw rh ymin ymax1 xmin xmax1
  104. 3 index 1 4 index 1 sub
  105. { currentdevice exch row copyscanlines .findzeros
  106. exch 4 1 roll .max 3 1 roll .min exch
  107. }
  108. for % xmin xmax1
  109. % Special check: xmin > xmax1 if height = 0
  110. 2 copy gt { exch pop dup } if
  111. 6 -2 roll pop pop
  112. } def
  113. % Write values on outfile.
  114. /w1 { 255 and outfile exch write } def
  115. /w2 { dup -8 bitshift w1 w1 } def
  116. /wbyte % <byte> <label> wbyte
  117. { VDEBUG { print ( =byte= ) print dup == flush } { pop } ifelse w1
  118. } def
  119. /wword % <word16> <label> wword
  120. { VDEBUG { print ( =word= ) print dup == flush } { pop } ifelse w2
  121. } def
  122. /wdword % <word32> <label> wdword
  123. { VDEBUG { print ( =dword= ) print dup == flush } { pop } ifelse
  124. dup -16 bitshift w2 w2
  125. } def
  126. /style.posture.keys
  127. [ { (Italic) } { (Oblique) }
  128. { }
  129. ] def
  130. /style.posture.values <010100> def
  131. /style.appearance.width.keys
  132. [ { (Ultra) (Compressed) }
  133. { (Extra) (Compressed) }
  134. { (Extra) (Condensed) }
  135. { (Extra) (Extended) }
  136. { (Extra) (Expanded) }
  137. { (Compressed) }
  138. { (Condensed) }
  139. { (Extended) }
  140. { (Expanded) }
  141. { }
  142. ] def
  143. /style.appearance.width.values <04030207070201060600> def
  144. /width.type.keys
  145. [ { (Ultra) (Compressed) }
  146. { (Extra) (Compressed) }
  147. { (Extra) (Condensed) }
  148. { (Extra) (Expanded) }
  149. { (Compressed) }
  150. { (Condensed) }
  151. { (Expanded) }
  152. { }
  153. ] def
  154. /width.type.values <fbfcfd03fdfe0200> def
  155. /stroke.weight.keys
  156. [ { (Ultra) (Thin) }
  157. { (Ultra) (Black) }
  158. { (Extra) (Thin) }
  159. { (Extra) (Light) }
  160. { (Extra) (Bold) }
  161. { (Extra) (Black) }
  162. { (Demi) (Light) }
  163. { (Demi) (Bold) }
  164. { (Semi) (Light) }
  165. { (Semi) (Bold) }
  166. { (Thin) }
  167. { (Light) }
  168. { (Bold) }
  169. { (Black) }
  170. { }
  171. ] def
  172. /stroke.weight.values <f907fafc0406fe02ff01fbfd030500> def
  173. /vendor.keys
  174. [ { (Agfa) }
  175. { (Bitstream) }
  176. { (Linotype) }
  177. { (Monotype) }
  178. { (Adobe) }
  179. { }
  180. ] def
  181. /vendor.default.index 4 def % might as well be Adobe
  182. /old.vendor.values <020406080a00> def
  183. /new.vendor.values <010203040500> def
  184. /vendor.initials (CBLMA\000) def
  185. currentdict readonly end pop % pcldict
  186. % Convert and write a PCL font for the current font and transformation.
  187. % Write the font header. We split this off only to avoid overflowing
  188. % the limit on the maximum size of a procedure.
  189. % Free variables: outfile uury u0y rw rh orientation uh ully
  190. /writefontheader
  191. { outfile (\033\)s) writestring
  192. outfile 64 WriteResolution? { 4 add } if
  193. Copyright length add write==only
  194. outfile (W) writestring
  195. WriteResolution? { 20 68 } { 0 64 } ifelse
  196. (Font Descriptor Size) wword
  197. (Header Format) wbyte
  198. 1 (Font Type) wbyte
  199. FullName style.posture.keys keysearch style.posture.values exch get
  200. FullName style.appearance.width.keys keysearch
  201. style.appearance.width.values exch get 4 mul add
  202. PaintType 2 eq { 32 add } if
  203. /style exch def
  204. style -8 bitshift (Style MSB) wbyte
  205. 0 (Reserved) wbyte
  206. /baseline uury 1 sub u0y sub def
  207. baseline (Baseline Position) wword
  208. rw (Cell Width) wword
  209. rh (Cell Height) wword
  210. orientation (Orientation) wbyte
  211. FontInfo /isFixedPitch .knownget not { false } if
  212. { 0 } { 1 } ifelse (Spacing) wbyte
  213. % Use loop/exit to fake a multiple-exit block.
  214. { Encoding StandardEncoding eq { 10 (J) exit } if
  215. Encoding ISOLatin1Encoding eq { 11 (J) exit } if
  216. Encoding SymbolEncoding eq { 19 (M) exit } if
  217. Encoding DingbatsEncoding eq { 10 (L) exit } if
  218. % (Warning: unknown Encoding, using ISOLatin1.\n) print flush
  219. 11 (J) exit
  220. }
  221. loop
  222. 0 get 64 sub exch 32 mul add (Symbol Set) wword
  223. ( ) stringwidth pop 0 dtransform add abs 4 mul
  224. /pitch exch def
  225. pitch cvi (Pitch) wword
  226. uh 4 mul (Height) wword % Height
  227. (x) charheight (x-Height) wword
  228. FullName width.type.keys keysearch
  229. width.type.values exch get (Width Type) wbyte
  230. style 255 and (Style LSB) wbyte
  231. FullName stroke.weight.keys keysearch
  232. stroke.weight.values exch get (Stroke Weight) wbyte
  233. FullName vendor.keys keysearch
  234. dup vendor.initials exch get 0 eq
  235. { % No vendor in FullName, try Notice
  236. pop Copyright vendor.keys keysearch
  237. dup vendor.initials exch get 0 eq { pop vendor.default.index } if
  238. }
  239. if
  240. /vendor.index exch def
  241. 0 (Typeface LSB) wbyte % punt
  242. 0 (Typeface MSB) wbyte % punt
  243. 0 (Serif Style) wbyte % punt
  244. 2 (Quality) wbyte
  245. 0 (Placement) wbyte
  246. gsave FontMatrix concat rot neg rotate
  247. /ulwidth
  248. FontInfo /UnderlineThickness .knownget
  249. { 0 exch dtransform exch pop abs }
  250. { resolution 100 div }
  251. ifelse def
  252. FontInfo /UnderlinePosition .knownget
  253. { 0 exch transform exch pop negY ulwidth 2 div add }
  254. { ully ulwidth add }
  255. ifelse u0y sub
  256. round cvi 1 .max 255 .min (Underline Position) wbyte
  257. ulwidth round cvi 1 .max 255 .min (Underline Thickness) wbyte
  258. grestore
  259. uh 1.2 mul 4 mul cvi (Text Height) wword
  260. (average lowercase character) dup stringwidth
  261. pop 0 dtransform add abs
  262. exch length div 4 mul cvi (Text Width) wword
  263. 0
  264. { dup Encoding exch get /.notdef ne { exit } if
  265. 1 add
  266. }
  267. loop (First Code) wword
  268. 255
  269. { dup Encoding exch get /.notdef ne { exit } if
  270. 1 sub
  271. }
  272. loop (Last Code) wword
  273. pitch dup cvi sub 256 mul cvi (Pitch Extended) wbyte
  274. 0 (Height Extended) wbyte
  275. 0 (Cap Height) wword % (default)
  276. currentfont /UniqueID known { UniqueID } { 0 } ifelse
  277. 16#c1000000 add (Font Number (Adobe UniqueID)) wdword
  278. FontName length 16 .max string
  279. dup FontName exch cvs pop
  280. outfile exch 0 16 getinterval writestring % Font Name
  281. WriteResolution?
  282. { resolution dup (X Resolution) wword (Y Resolution) wword
  283. }
  284. if
  285. outfile Copyright writestring % Copyright
  286. } def
  287. /writePCL % <fontfile> <resolution> writePCL -
  288. {
  289. save
  290. currentfont begin
  291. pcldict begin
  292. 80 dict begin % allow for recursion
  293. /saved exch def
  294. /resolution exch def
  295. /outfile exch def
  296. matrix currentmatrix dup 4 0 put dup 5 0 put setmatrix
  297. % Supply some default values so we don't have to check later.
  298. currentfont /FontInfo known not { /FontInfo 1 dict def } if
  299. currentfont /FontName known not { /FontName () def } if
  300. /Copyright FontInfo /Notice .knownget not { () } if def
  301. /FullName
  302. FontInfo /FullName .knownget not
  303. { FontName dup length string cvs }
  304. if def
  305. % Determine the original font, and its relationship to this one.
  306. /OrigFont currentfont origfont def
  307. /OrigMatrix OrigFont /FontMatrix get def
  308. /OrigMatrixInverse OrigMatrix matrix invertmatrix def
  309. /ScaleMatrix matrix currentfont OrigFont ne
  310. { FontMatrix exch OrigMatrixInverse exch concatmatrix
  311. } if
  312. def
  313. /CurrentScaleMatrix
  314. matrix currentmatrix
  315. matrix defaultmatrix
  316. dup 0 get 1 index 3 get mul 0 lt
  317. 1 index dup 1 get exch 2 get mul 0 gt or
  318. /flipY exch def
  319. dup invertmatrix
  320. dup concatmatrix
  321. def
  322. /negY flipY { {neg} } { {} } ifelse def
  323. % Print debugging information.
  324. /CDEBUG where { pop } { /CDEBUG false def } ifelse
  325. /VDEBUG where { pop } { /VDEBUG false def } ifelse
  326. CDEBUG { /VDEBUG true def } if
  327. DEBUG
  328. { (currentmatrix: ) print matrix currentmatrix ==
  329. (defaultmatrix: ) print matrix defaultmatrix ==
  330. (flipY: ) print flipY ==
  331. (scaling matrix: ) print CurrentScaleMatrix ==
  332. (FontMatrix: ) print FontMatrix ==
  333. (FontBBox: ) print /FontBBox load ==
  334. currentfont OrigFont ne
  335. { OrigFont /FontName .knownget { (orig FontName: ) print == } if
  336. (orig FontMatrix: ) print OrigMatrix ==
  337. } if
  338. currentfont /ScaleMatrix .knownget { (ScaleMatrix: ) print == } if
  339. gsave
  340. FontMatrix concat
  341. (combined matrix: ) print matrix currentmatrix ==
  342. grestore
  343. flush
  344. } if
  345. % Determine the orientation.
  346. ScaleMatrix matrix currentmatrix dup concatmatrix
  347. 0 1 3
  348. { 1 index 1 get 0 eq 2 index 2 get 0 eq and 2 index 0 get 0 gt and
  349. { exit } if
  350. pop -90 matrix rotate exch dup concatmatrix
  351. }
  352. for
  353. dup type /integertype ne
  354. { (Only rotations by multiples of 90 degrees are supported:\n) print
  355. == flush
  356. saved end end end restore stop
  357. }
  358. if
  359. /orientation exch def
  360. /rot orientation 90 mul def
  361. DEBUG { (orientation: ) print orientation == flush } if
  362. dup dup 0 get exch 3 get negY sub abs 0.5 ge
  363. { (Only identical scaling in X and Y is supported:\n) print
  364. exch flipY 3 array astore ==
  365. currentdevice .devicename ==
  366. matrix defaultmatrix == flush
  367. saved end end end restore stop
  368. }
  369. if pop
  370. % Determine the font metrics, in the PCL character coordinate system,
  371. % which has +Y going towards the top of the page.
  372. gsave
  373. FontMatrix concat
  374. 0 0 transform
  375. negY round cvi /r0y exch def
  376. round cvi /r0x exch def
  377. ixbbox
  378. negY /rury exch def /rurx exch def
  379. negY /rlly exch def /rllx exch def
  380. /rminx rllx rurx .min def
  381. /rminy rlly negY rury negY .min def
  382. /rw rurx rllx sub abs def
  383. /rh rury rlly sub abs def
  384. gsave rot neg rotate
  385. 0 0 transform
  386. negY round cvi /u0y exch def
  387. round cvi /u0x exch def
  388. ixbbox
  389. negY /uury exch def /uurx exch def
  390. negY /ully exch def /ullx exch def
  391. /uw uurx ullx sub def
  392. /uh uury ully sub def
  393. grestore
  394. DEBUG
  395. { (rmatrix: ) print matrix currentmatrix ==
  396. (rFontBBox: ) print [rllx rlly rurx rury] ==
  397. (uFontBBox: ) print [ullx ully uurx uury] ==
  398. flush
  399. } if
  400. grestore
  401. % Disable the character cache, to avoid excessive allocation
  402. % and memory sandbars.
  403. mark cachestatus /upper exch def
  404. cleartomark 0 setcachelimit
  405. % Write the font header.
  406. writefontheader
  407. % Establish an image device for rasterizing characters.
  408. matrix currentmatrix
  409. dup 4 rminx neg put
  410. dup 5 rminy neg put
  411. % Round the width up to a multiple of 8
  412. % so we don't get garbage bits in the last byte of each row.
  413. rw 7 add -8 and rh <ff 00> makeimagedevice
  414. /cdevice exch def
  415. nulldevice % prevent page device switching
  416. cdevice setdevice
  417. % Rasterize each character in turn.
  418. /raster rw 7 add 8 idiv def
  419. /row raster string def
  420. /zerow row length string def
  421. 0 1 Encoding length 1 sub
  422. { /cindex exch def
  423. Encoding cindex get /.notdef ne
  424. { VDEBUG { Encoding cindex get == flush } if
  425. erasepage initgraphics
  426. 0 0 moveto currentpoint transform add
  427. ( ) dup 0 cindex put show
  428. currentpoint transform add exch sub round cvi
  429. /cwidth exch abs def
  430. rw rh devbbox
  431. VDEBUG
  432. { (image bbox: ) print 4 copy 4 2 roll 4 array astore == flush
  433. } if
  434. % Save the device bounding box.
  435. % Note that this is in current device coordinates,
  436. % not PCL (right-handed) coordinates.
  437. /bqx exch def /bpx exch def /bqy exch def /bpy exch def
  438. % Re-render with the character justified to (0,0).
  439. % This may be either the lower left or the upper left corner.
  440. bpx neg bpy neg idtransform moveto
  441. erasepage
  442. VDEBUG { (show point: ) print [ currentpoint transform ] == flush } if
  443. ( ) dup 0 cindex put show
  444. % Find the bounding box. Note that xmin and ymin are now 0,
  445. % xmax1 = xw, and ymax1 = yh.
  446. rw rh devbbox
  447. /xw exch def
  448. % xmin or ymin can be non-zero only if the character is blank.
  449. xw 0 eq
  450. { pop }
  451. { dup 0 ne { (Non-zero xmin! ) print = } { pop } ifelse }
  452. ifelse
  453. /yh exch def
  454. yh 0 eq
  455. { pop }
  456. { dup 0 ne { (Non-zero ymin! ) print = } { pop } ifelse }
  457. ifelse
  458. /xbw xw 7 add 8 idiv def
  459. /xright raster 8 mul xw sub def
  460. % Write the Character Code command.
  461. outfile (\033*c) writestring
  462. outfile cindex write==only
  463. outfile (E) writestring
  464. % Write the Character Definition command.
  465. outfile (\033\(s) writestring
  466. yh xbw mul 16 add
  467. outfile exch write=only
  468. % Record the character position for the .PCM file.
  469. /cfpos outfile fileposition 1 add def
  470. outfile (W\004\000\016\001) writestring
  471. orientation (Orientation) wbyte 0 (Reserved) wbyte
  472. rminx bpx add r0x sub (Left Offset) wword
  473. flipY { rminy bpy add neg } { rminy bqy add } ifelse r0y sub
  474. (Top Offset) wword
  475. xw (Character Width) wword
  476. yh (Character Height) wword
  477. cwidth orientation 2 ge { neg } if 4 mul (Delta X) wword
  478. % Write the character data.
  479. flipY { 0 1 yh 1 sub } { yh 1 sub -1 0 } ifelse
  480. { cdevice exch row copyscanlines
  481. 0 xbw getinterval
  482. CDEBUG
  483. { dup
  484. { 8
  485. { dup 128 ge { (+) } { (.) } ifelse print
  486. 127 and 1 bitshift
  487. }
  488. repeat pop
  489. }
  490. forall (\n) print
  491. }
  492. if
  493. outfile exch writestring
  494. }
  495. for
  496. }
  497. { /bpx 0 def /bpy 0 def /bqx 0 def /bqy 0 def
  498. /cwidth 0 def
  499. /cfpos 0 def
  500. }
  501. ifelse
  502. }
  503. for
  504. % Wrap up.
  505. upper setcachelimit
  506. outfile closefile
  507. nulldevice % prevent page device switching
  508. saved end end end restore
  509. } def
  510. % Provide definitions for testing with older or non-custom interpreters.
  511. /.findzeros where { pop (%END) .skipeof } if
  512. /.findzeros
  513. { userdict begin /zs exch def /zl zs length def
  514. 0 { dup zl ge { exit } if dup zs exch get 0 ne { exit } if 1 add } loop
  515. zl { dup 0 eq { exit } if dup 1 sub zs exch get 0 ne { exit } if 1 sub } loop
  516. exch 3 bitshift exch 3 bitshift
  517. 2 copy lt
  518. { exch zs 1 index -3 bitshift get
  519. { dup 16#80 and 0 ne { exit } if exch 1 add exch 1 bitshift } loop pop
  520. exch zs 1 index -3 bitshift 1 sub get
  521. { dup 1 and 0 ne { exit } if exch 1 sub exch -1 bitshift } loop pop
  522. }
  523. if end
  524. } bind def
  525. %END
  526. /write=only where { pop (%END) .skipeof } if
  527. /w=s 128 string def
  528. /write=only
  529. { w=s cvs writestring
  530. } bind def
  531. %END
  532. %**************** Test
  533. /PCLTEST where {
  534. pop
  535. /DEBUG true def
  536. /CDEBUG true def
  537. /VDEBUG true def
  538. /Times-Roman findfont 10 scalefont setfont
  539. (t.pcf) (w) file
  540. 300 72 div dup scale
  541. 300 writePCL
  542. flush quit
  543. } if