home *** CD-ROM | disk | FTP | other *** search
/ jppd.dyndns.org / jppd.dyndns.org.tar / jppd.dyndns.org / QUERYPRO / Impressora_PDF / converter.exe / GPLGS / bdftops.ps < prev    next >
Text File  |  2003-12-13  |  24KB  |  796 lines

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