home *** CD-ROM | disk | FTP | other *** search
/ Acorn User 10 / AU_CD10.iso / Updates / GhostScript / !GhostScr / 6_01 / lib / bdftops.ps < prev    next >
Text File  |  2000-03-09  |  23KB  |  795 lines

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