home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / fontutils-0.6 / gsrenderfont / writefont.PS < prev    next >
Encoding:
Text File  |  1992-10-23  |  21.1 KB  |  826 lines

  1. % writefont.PS: make a bitmap and image-information file for a font.
  2. % Copyright (C) 1992 Free Software Foundation, Inc.
  3. %
  4. % This program is free software; you can redistribute it and/or modify
  5. % it under the terms of the GNU General Public License as published by
  6. % the Free Software Foundation; either version 2, or (at your option)
  7. % any later version.
  8. %
  9. % This program is distributed in the hope that it will be useful,
  10. % but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. % GNU General Public License for more details.
  13. %
  14. % You should have received a copy of the GNU General Public License
  15. % along with this program; if not, write to the Free Software
  16. % Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. 100 dict begin % our local environment
  19.  
  20. /verbose false def
  21.  
  22.  
  23. % Utilities.
  24.  
  25. % Traditional.
  26. /bdef { bind def } bind def
  27.  
  28.  
  29. % /VAR incr  sets /VAR to VAR + 1.
  30. /incr { dup load 1 add def } bdef
  31.  
  32.  
  33. % /VAR NUMBER max=  sets /VAR to the maximum of VAR and NUMBER.
  34. /max= { 1 index load max def } bdef
  35.  
  36.  
  37. % Print a string if we are verbose, else do nothing.
  38. /vreport { verbose { = } { pop } ifelse } bdef
  39.  
  40.  
  41.  
  42. % DICT pdict prints all the components in the dictionary in a
  43. % human-readable way.
  44. /pdict
  45. {
  46.     { exch
  47.       dup =only length 8 lt {(\t) =only } if
  48.       (\t=> ) =only
  49.       ==
  50.     }
  51.   forall
  52. }
  53. bdef
  54.  
  55.  
  56. % Point and pixel conversions.
  57. /inches-per-pixel {1 pixels-per-inch div} bdef
  58.  
  59. % Use the real definition of points, not PostScript's.
  60. /points-per-inch 72 def
  61. /inches-per-point 1 points-per-inch div def
  62.  
  63. /points-per-pixel {points-per-inch inches-per-pixel mul} bdef
  64. /pixels-per-point {pixels-per-inch inches-per-point mul} bdef
  65.  
  66. /points {points-per-pixel mul} bdef    % Use on stuff expressed in pixels.
  67. /pixels {pixels-per-point mul} bdef    % Use on stuff expressed in points.
  68.  
  69. % Make a new font whose PostScript name is `/newfont', which is the same
  70. % as the font with name `gs-fontname' (read from file `input-filename'
  71. % if necessary) except it has encoding `output-encoding'.
  72. % Set the currentfont to /newfont scaled to `point-size'.
  73. /set-font
  74. {
  75.   % Make the new font /newfont.
  76.   input-filename gs-fontname cvlit /newfont output-encoding reencode-font
  77.  
  78.   % Make it the current font (at the requested size).
  79.   /newfont findfont point-size cvi scalefont setfont
  80.  
  81.   % Define the global `font-encoding' for future use.
  82.   /font-encoding currentfont /Encoding get def
  83. }
  84. bdef
  85.  
  86.  
  87. % (OLD-FILENAME) /OLD-FONTNAME /NEW-FONTNAME NEW-ENCODING reencode-font
  88. % defines the font NEW-FONTNAME to be like OLD-FONTNAME except that the
  89. % encoding is NEW-ENCODING.  Based on the Cookbook encoding examples.
  90. % We read OLD-FILENAME if /OLD-FONTNAME is unknown to Ghostscript.  We
  91. % determine this by looking at the dictionary `Fontmap' that Ghostscript
  92. % defines when it starts up.
  93. /reencode-font
  94. {
  95.   /new-encoding exch def
  96.   /new-fontname exch def
  97.   /old-fontname exch def
  98.   /old-filename exch def
  99.  
  100.   % If OLD-FONTNAME is not in `Fontmap', read OLD-FILENAME.
  101.   Fontmap old-fontname cvn known  not
  102.     { (Reading `) old-filename concatstrings ('...) concatstrings vreport
  103.       old-filename run
  104.  
  105.       % If reading OLD-FILENAME didn't define OLD-FONTNAME, complain.
  106.       FontDirectory old-fontname cvn known  not
  107.         { (Reading `) =only
  108.           old-filename =only
  109.           (' didn't define the font `) =only
  110.           old-fontname =only
  111.           ('!) =
  112.           quit
  113.         }
  114.       if
  115.     }
  116.   if
  117.  
  118.   % Get the old font, and make the dictionary that will be the new font.
  119.   /old-fontdict old-fontname findfont def
  120.   /new-fontdict old-fontdict maxlength dict def
  121.  
  122.   % Copy all the elements except `FID', `Encoding', and `FontName'.
  123.   old-fontdict
  124.     {
  125.       exch % now have key at top the stack
  126.       dup /FID eq  1 index /Encoding eq  2 index /FontName eq  or or
  127.         { pop pop}
  128.         { exch new-fontdict 3 1 roll put }
  129.       ifelse
  130.     }
  131.   forall
  132.  
  133.   % But if NEW-ENCODING is this sentinel value, we copy the existing
  134.   % encoding vector.
  135.   % 
  136.   new-encoding (/encoding-from-input) eq
  137.     {
  138.       /new-encoding old-fontdict /Encoding get 256 array copy def
  139.     }
  140.   if
  141.   
  142.   % Get another encoding array, this one a subset of NEW-ENCODING, which
  143.   % contains only those characters that are actually present in the font
  144.   % -- sometimes the encoding vectors lie.
  145.   % 
  146.   new-fontdict new-encoding encoding-chars-present
  147.   /ok-encoding exch def
  148.  
  149.   % Install the new Encoding and FontName.  The 10-character limit on
  150.   % the FontName is not serious, since we are the ones who specify it
  151.   % (in fact, new-fontname is the name `/newfont').
  152.   new-fontdict /Encoding ok-encoding put
  153.   new-fontdict /FontName new-fontname 10 string cvs put
  154.  
  155.   % Define the font.
  156.   new-fontname new-fontdict definefont pop
  157. }
  158. bdef % reencode-font
  159.  
  160.  
  161. % FONT-DICT ENCODING encoding-chars-present => NEW-ENCODING returns an
  162. % encoding vector contain all and only those characters which are
  163. % present in both the font represented by FONT-DICT (which lacks an
  164. % Encoding entry) and ENCODING.
  165. % We have to use different algorithms for Type 1 and Type 3 fonts.
  166. /encoding-chars-present
  167. {
  168.   /font-type 2 index /FontType get def
  169.   
  170.   font-type 1 eq
  171.     { encoding-chars-present-1 }
  172.     { encoding-chars-present-3 }
  173.   ifelse
  174. }
  175. bdef % encoding-chars-present
  176.  
  177.  
  178. % (See encoding-chars-present).  For Type 1 fonts, we can just look in
  179. % the CharStrings entry (which is required) of FONT-DICT.
  180. /encoding-chars-present-1
  181. {
  182.   /orig-encoding exch def
  183.   /font-dict exch def
  184.   
  185.   /font-charstrings font-dict /CharStrings get def
  186.   
  187.   /new-encoding 256 array def
  188.   /charcode 0 def
  189.   
  190.   % For each element in the old vector, see if it's in `CharStrings'.
  191.     orig-encoding
  192.     {   font-charstrings 1 index known
  193.         { new-encoding charcode 3 -1 roll put }
  194.         { new-encoding charcode /.notdef put  pop }
  195.       ifelse
  196.       /charcode incr
  197.     }
  198.   forall
  199.   
  200.   % Return the new vector.
  201.   new-encoding
  202. }
  203. bdef
  204.  
  205.  
  206. % (See encoding-chars-present).  For Type 3 fonts, the character
  207. % definitions might be in a dictionary named anything at all.  Heck,
  208. % there might not even be a dictionary.  So the best I can think of is
  209. % to try to render each character; if it succeeds, we'll say it's
  210. % present, and if it fails, we'll omit it.
  211. % We change the current font to be the one specified by FONT-DICT.
  212. % (Since we're going to change fonts again right after we return,
  213. % there's no point in saving and restoring.)
  214. /encoding-chars-present-3
  215. {
  216.   /orig-encoding exch def
  217.   /font-dict exch def
  218.   
  219.   /new-encoding 256 array def
  220.   
  221.   % Set up the current font.
  222.   font-dict orig-encoding type3-setfont
  223.   
  224.   % Have to have a current point for `show' to work.
  225.   % 
  226.   0 0 moveto
  227.   
  228.   % For each element in the old vector, see if we can render it.
  229.   0 1 255
  230.     { dup type3-render-p
  231.         % Push the name we will put in the new vector.
  232.         { orig-encoding 1 index  get }
  233.         { /.notdef }
  234.       ifelse
  235.  
  236.       % Now have charcode and charname on the stack.
  237.       new-encoding 3 1 roll put
  238.     }
  239.   for
  240.   
  241.   % Return the new vector.
  242.   new-encoding
  243. }
  244. bdef
  245.  
  246.  
  247. % FONT-DICT ENCODING type3-setfont sets the current font to be the one
  248. % represented by FONT-DICT.  We have to set up the encoding vector and
  249. % do the definefont ourselves.
  250. /type3-setfont
  251. {
  252.   /test-encoding exch def
  253.   /font-dict exch def
  254.   
  255.   % Use our new encoding in the test font.
  256.   font-dict /Encoding test-encoding put
  257.   
  258.   % Have to copy the dictionary explicitly, else it will become readonly
  259.   % and we won't be able to change the encoding for real later.
  260.   % 
  261.   font-dict dup maxlength dict copy
  262.   /type3-testfont exch definefont setfont
  263. }
  264. bdef
  265.  
  266.  
  267. % CHARCODE type3-render-p => bool returns true if rendering CHARCODE
  268. % does not produce an error.  We assume the current font is set to the
  269. % right thing.
  270. /type3-render-p
  271. {
  272.   /char exch def
  273.   put-char-in-buffer
  274.  
  275.   % If the BuildChar fails, make sure no junk is left on the operand or
  276.   % dictionary stacks.
  277.   countdictstack
  278.   mark
  279.   
  280.   % Render the character
  281.   { char-buffer show } stopped not
  282.   
  283.   % Since we need to clear the operand stack, we have to save the
  284.   % result.  But since we're going to clear the dictionary stack also,
  285.   % we have to explicitly use our dictionary.
  286.   envGSRF /ok 3 -1 roll put
  287.   
  288.   cleartomark
  289.     {
  290.       dup countdictstack eq { exit } if
  291.       end
  292.     }
  293.   loop
  294.   pop % The original `countdictstack' value.
  295.   
  296.   % Return whether or not we succeeded.
  297.   ok
  298. }
  299. bdef
  300.  
  301. % ENCODING-NAME find-encoding ENCODING reads the encoding file
  302. % `ENCODING-NAME.enc' unless ENCODING-NAME is a sentinel value, in which
  303. % case we just return it.
  304. /find-encoding
  305. {
  306.   dup (/encoding-from-input) eq not
  307.     { parse-encoding-file }
  308.   if
  309. }
  310. bdef
  311.  
  312.  
  313. % (FILENAME) parse-encoding-file tries to read the encoding file
  314. % `FILENAME.enc'.  If the file can't be found, we quit.  Otherwise, we
  315. % parse it into an encoding vector and return that on the stack.
  316. /parse-encoding-file
  317. {
  318.   /charcode 0 def
  319.  
  320.   open-encoding-file 
  321.  
  322.   % We've opened the file.  Begin the encoding array.
  323.   256 array
  324.   
  325.   % Ignore the coding scheme (assumption here that the .enc file does
  326.   % not have zero or one non-blank non-comment lines, i.e., is empty or
  327.   % just a comment):
  328.   encoding-line pop
  329.  
  330.   % Read the rest of file:
  331.     {
  332.       % If at EOF, stop.
  333.       encoding-line dup null eq
  334.         { pop exit }
  335.       if
  336.  
  337.       % Otherwise, we're at the next character.  Define it.
  338.       1 index    % array charname  on the stack.
  339.       exch    % charname array
  340.       charcode    % charcode charname array
  341.       exch    % charname charcode array
  342.       put
  343.       
  344.       % We're on the next character code.
  345.       /charcode incr
  346.     }
  347.   loop
  348.   
  349.   % The .enc file is not required to define all 256 characters.  Any
  350.   % character codes after the last one in the file go to .notdef.
  351.   charcode 1 255
  352.     {
  353.       1 index    % array charcode
  354.       exch    % charcode array
  355.       /.notdef
  356.       put
  357.     }
  358.   for
  359.   
  360.   % Leave the array on the stack as the return value.
  361. }
  362. bdef
  363.  
  364.  
  365. % FILENAME open-encoding-file opens `encodingfile' as FILENAME.enc, or quits.
  366. /open-encoding-file
  367. {
  368.   (.enc) concatstrings
  369.   findlibfile
  370.     { exch pop /encodingfile exch def }
  371.     { =only (: Cannot find encoding file.) = quit }
  372.   ifelse
  373. }
  374. bdef
  375.  
  376.  
  377. % encoding-line reads to the next non-blank non-comment line in the
  378. % `encodingfile'.  If we hit EOF, it returns null.  Otherwise, it
  379. % returns the first token on the line (i.e., a name).
  380. % Sorry about this hard limit, but I don't want to program variable
  381. % strings in PostScript.
  382. /line-buffer 1000 string def
  383.  
  384. /encoding-line
  385. {
  386.   % Read lines from `encodingfile' until we get to one that is neither blank
  387.   % nor starts with a comment.
  388.     {
  389.       encodingfile line-buffer readline
  390.         % If can get a token, pop the rest of the string after it, and
  391.         % return that first token (it is a name object).
  392.         { token { exch pop cvlit exit } if }
  393.         
  394.         % At EOF, return null.
  395.         { pop null exit }
  396.       ifelse
  397.     }
  398.   loop
  399. }
  400. bdef % encoding-line
  401.  
  402. % Expects a character code on the stack.  Sets /char to that integer,
  403. % /char-name to the character name for that code in the Encoding vector,
  404. % and /char-in-font to either true or false.
  405. /set-char-variables
  406. {
  407.    /char exch def
  408.    /char-name font-encoding char get def
  409.  
  410.    % There's no point in outputting .notdef.
  411.    /char-in-font  char-name /.notdef ne  def
  412. }
  413. bdef
  414.  
  415.  
  416. % Expects the integer representation of a character in `char'.
  417. /char-buffer 1 string def
  418.  
  419. /put-char-in-buffer
  420. {
  421.   char-buffer 0 char put
  422. }
  423. bdef
  424.  
  425.  
  426. % Expects to find the character in char-buffer.  Sets dimensions in pixels.
  427. /find-char-dimensions-in-pixels
  428. {
  429.   gsave
  430.     newpath
  431.     0 0 moveto
  432.  
  433.     char-buffer true charpath      
  434.     flattenpath
  435.     pathbbox % returns ury urx lly llx
  436.       /char-height exch pixels def
  437.       /char-width exch pixels def
  438.       /char-depth exch pixels def
  439.       /char-left-sidebearing exch pixels def
  440.       
  441.       % The bounding-box width is urx - llx.
  442.       /char-width char-width char-left-sidebearing sub def
  443.       
  444.       % The bounding-box height is ury - lly.
  445.       /char-tall char-height char-depth sub def
  446.       
  447.       % The set width.
  448.       /char-stringwidth char-buffer stringwidth pop pixels def
  449.  
  450.       /char-right-sidebearing        % Calculate in terms of pixels.
  451.         char-stringwidth
  452.           char-width sub
  453.           char-left-sidebearing sub
  454.       def
  455.   grestore
  456. }
  457. bdef % find-char-dimensions-in-pixels
  458.  
  459. % If the char is defined in the font, show it on on a line by itself, ni
  460. % a space that is max-char-tall-in-pixels pixels high.
  461. % Expects an integer, the character code to show.
  462. /show-char
  463. {
  464.   set-char-variables
  465.   char-in-font
  466.     {
  467.       put-char-in-buffer
  468.       find-char-dimensions-in-pixels
  469.       %%char-name print-char-dimensions %%
  470.  
  471.       % If the lsb is negative, the character protrudes to the left of
  472.       % its reference point, so we have to move the current point over
  473.       % to the right, so we image the entire thing.
  474.           char-left-sidebearing 0 lt { char-left-sidebearing neg } { 0 } ifelse
  475.         points
  476.         char-height ceiling points neg
  477.       rmoveto
  478.  
  479.       % Show the character.
  480.       char-buffer show
  481.  
  482.       % Move to the beginning of the next line.
  483.       currentpoint exch pop 0 exch moveto
  484.       
  485.       % Leave enough blank rows to fill up the max-char-tall-in-pixels
  486.       % space.  This will always be more than the descender.
  487.       0  max-char-tall-in-pixels char-height ceiling sub points neg  rmoveto
  488.     }
  489.   if
  490. }
  491. bdef % show-char
  492.  
  493.  
  494. % Expects a label string.
  495. /print-char-dimensions
  496. {
  497.   /label exch def
  498.   verbose 
  499.     {() = label =
  500.      char-buffer (char: ) =only = 
  501.      char-height (char-height: ) =only =
  502.      char-depth (char-depth: ) =only =
  503.      char-tall (char-tall: ) =only =
  504.      char-stringwidth (char-stringwidth: ) =only =
  505.      char-width (char-width: ) =only =
  506.      char-left-sidebearing (char-left-sidebearing: ) =only =
  507.      char-right-sidebearing (char-right-sidebearing: ) =only =
  508.      flush
  509.     }
  510.   if
  511. }
  512. bdef % print-char-dimensions
  513.  
  514. % IFI stuff.
  515.  
  516. /max-output-buffer 100 def
  517. /output-buffer max-output-buffer string def
  518.  
  519.  
  520. /ifi-charname
  521. {
  522.   char-name output-buffer cvs
  523.   %verbose { char-name =only  ( @ ) =only char = } if
  524. }
  525. bdef
  526.  
  527. % We round the character's depth.
  528. /baseline-adjustment
  529. {
  530.   char-depth round cvi 1 sub neg output-buffer cvs
  531. }
  532. bdef
  533.  
  534. % We cannot easily compute the number of bounding boxes in a rendered
  535. % character in Ghostscript.  A `%' might have three bounding boxes at a
  536. % high resolution, but only two at a lower one (one of the circles might
  537. % touch the slash).  So we use an external program, `bbcount'. 
  538. /num-bounding-boxes
  539. {
  540.   (00)
  541. }
  542. bdef
  543.  
  544. /side-bearings
  545. {
  546.   char-left-sidebearing round output-buffer cvs
  547.   ( ) concatstrings
  548.   char-right-sidebearing round output-buffer cvs 
  549.   concatstrings
  550. }
  551. bdef
  552.  
  553. % Expects an integer, the character code.  If the char is defined in the
  554. % font and the output encoding, output it.  That is, output the
  555. % character code, baseline adjustment, number of bounding boxes, and
  556. % left and right sidebearings.
  557. /output-char-info
  558. {
  559.   set-char-variables
  560.   char-in-font 
  561.     {
  562.       put-char-in-buffer
  563.       find-char-dimensions-in-pixels
  564.  
  565.       ifi-charname ifi-writestring
  566.       baseline-adjustment ifi-writestring
  567.       num-bounding-boxes ifi-writestring
  568.       side-bearings ifi-writestring
  569.       ifi-file (\n) writestring
  570.     }
  571.   if % char-in-font 
  572. }
  573. bdef % output-char-info
  574.  
  575.  
  576. % STRING ifi-writestring writes STRING to ifi-file, followed by a space.
  577. /ifi-writestring
  578. {
  579.   ifi-file exch writestring
  580.   ifi-file ( ) writestring
  581. }
  582. bdef
  583.  
  584. % Expects a label string.
  585. /print-current-device
  586. {
  587.   /label exch def
  588.   (\n) = label =
  589.   currentdevice getdeviceprops
  590.   (Current device's height, width and matrix are: ) =print = = == flush
  591.   cleartomark
  592. }
  593. bdef
  594.  
  595. % Make and set a monochrome image device with the normal PostScript
  596. % convention: (0,0) is at the lower left.  Expects a device
  597. % resolution, height, and width.
  598. /make-image-device
  599. {
  600.   /width exch def
  601.   /height exch def
  602.   /scale-factor exch def
  603.  
  604.     [scale-factor 0 0 scale-factor neg 0 height]
  605.     width height
  606.     <ff 00>
  607.   makeimagedevice 
  608.   setdevice
  609.   erasepage
  610. }
  611. bdef % make-image-device
  612.  
  613. % Figure out the maximum height + depth and width over all characters.
  614. % Also count the number of characters we will eventually output.
  615. /compute-max-char-dimens
  616. {
  617.   (Computing maximum character dimensions...) vreport
  618.  
  619.   /max-char-width-in-pixels 0 def
  620.   /max-char-tall-in-pixels 0 def
  621.   /extant-char-count 0 def
  622.   
  623.   0 1 255
  624.     {
  625.       set-char-variables
  626.       char-in-font
  627.         {
  628.           /extant-char-count incr
  629.  
  630.           put-char-in-buffer
  631.           find-char-dimensions-in-pixels
  632.  
  633.           % The set width might be smaller than the bounding box if we
  634.           % have negative side bearings.
  635.           char-stringwidth char-width max
  636.           /max-char-width-in-pixels exch max=
  637.           
  638.           % Accents (for example) might have a positive depth, and thus
  639.           % the height will be less than the height + depth, and what we
  640.           % want is the largest y coordinate.
  641.           /max-char-tall-in-pixels char-tall char-height max max=
  642.         }
  643.       if
  644.     }
  645.   for
  646.  
  647.   % We also want to have some blank rows between characters.  The
  648.   % constant here is also used in bbcount's pbm-reading routines.
  649.   /max-char-tall-in-pixels
  650.     max-char-tall-in-pixels ceiling  4 add  cvi
  651.   def
  652.   
  653.   verbose
  654.     {
  655.       max-char-width-in-pixels (  max-char-width-in-pixels: )=only =
  656.       max-char-tall-in-pixels  (   max-char-tall-in-pixels: )=only =
  657.       flush
  658.     }
  659.   if
  660. }
  661. bdef % compute-max-char-dimens
  662.  
  663.  
  664. % We use the max character dimensions to figure out the final size of
  665. % the device.  We also need to add a couple pixels to account for
  666. % roundoff error.  And makeimagedevice works with integers only.
  667. % We will output each character in a space max-char-tall-in-pixels high.
  668. % This makes it easier to write the `bbcount' program, at the expense of
  669. % making the PBM file somewhat larger.  Since the PBM file is only
  670. % temporary, I thought it was worth it.  We cannot compute the bounding
  671. % boxes ourselves without essentially implementing bbcount in
  672. % Ghostscript -- a task I thought extremely unappealing.
  673. /compute-final-device-dimens
  674. {
  675.   (Computing final device dimensions...) vreport
  676.  
  677.   /device-width-in-pixels max-char-width-in-pixels ceiling cvi
  678.   def
  679.   /device-height-in-pixels max-char-tall-in-pixels extant-char-count mul cvi
  680.   def
  681.  
  682.   verbose
  683.     {
  684.       device-width-in-pixels  (   device-width-in-pixels: )=only =
  685.       device-height-in-pixels (  device-height-in-pixels: )=only =
  686.       flush
  687.     }
  688.   if
  689.  
  690.   device-height-in-pixels 0 eq
  691.     { (Device height would be zero.  No characters?) = flush quit }
  692.   if
  693. }
  694. bdef % compute-final-device-dimens
  695.  
  696. % make-gsfont, the main program.
  697.  
  698. % Arguments:
  699. %   gs-fontname        (e.g., Times-Roman -- no slash in front)
  700. %   input-filename    (e.g., ptmr -- unused if the font is in Fontmap)
  701. %   output-filename    (e.g., ptmr -- to get ptmr.pbm and ptmr.ifi)
  702. %   point-size        (e.g., 10 -- in PostScript points)
  703. %   pixels-per-inch    (e.g., 300 -- can't have nonsquare pixels)
  704. %   encoding-filename    (e.g., textext -- to find .enc file)
  705. % (Except `encoding-filename' might be a sentinel value, not a filename.)
  706. /make-gsfont
  707. {
  708.   /gs-fontname exch def
  709.   /input-filename exch def
  710.   /output-filename exch def
  711.   /point-size exch cvi def
  712.   /pixels-per-inch exch cvi def
  713.   /encoding-filename exch def
  714.  
  715.   % Look for the file `encoding-filename.enc' and parse it,
  716.   % returning an encoding dictionary.
  717.   % 
  718.     (Using encoding `) encoding-filename concatstrings
  719.     (' for output...) concatstrings
  720.   vreport
  721.   /output-encoding encoding-filename find-encoding def
  722.  
  723.   % Now that we know the output encoding, we can make the font we're
  724.   % going to render the current font.
  725.   % 
  726.   (Reencoding and setting font...) vreport
  727.   set-font
  728.  
  729.   % First make an image device one inch square for finding heights of
  730.   % all the characters.  We should make it larger if necessary, i.e., if
  731.   % a character is larger than 1", but we don't.
  732.   %
  733.   pixels-per-point pixels-per-inch pixels-per-inch make-image-device
  734.  
  735.   compute-max-char-dimens
  736.  
  737.   compute-final-device-dimens
  738.  
  739.   % Now we know how many pixels we'll need to output the whole font.  So
  740.   % make another device that is big enough.
  741.   % 
  742.     pixels-per-point device-height-in-pixels device-width-in-pixels
  743.   make-image-device    
  744.  
  745.   % Move to the upper left-hand corner.
  746.   % 
  747.   0 device-height-in-pixels points moveto
  748.  
  749.   (Rendering characters to memory...) vreport
  750.   0 1 255 { show-char } for
  751.  
  752.   (Writing PBM file...) vreport
  753.   /pbm-filename output-filename (.pbm) concatstrings def
  754.   /pbm-file pbm-filename (w) file def
  755.   pbm-file currentdevice writeppmfile
  756.   pbm-file closefile
  757.  
  758.   (Writing BFI file...) vreport
  759.   /bfi-filename output-filename (.bfi) concatstrings def
  760.   /bfi-file bfi-filename (w) file def
  761.   bfi-file extant-char-count output-buffer cvs writestring
  762.   bfi-file (\n) writestring
  763.   bfi-file max-char-tall-in-pixels output-buffer cvs writestring
  764.   bfi-file (\n) writestring
  765.   bfi-file closefile
  766.   
  767.   (Writing XIFI file...) vreport
  768.   /ifi-filename output-filename (.xifi) concatstrings def
  769.   /ifi-file ifi-filename (w) file def
  770.   0 1 255 { output-char-info } for
  771.   ifi-file closefile 
  772. }
  773. bdef  % End of main program
  774.  
  775.  
  776. currentdict end /envGSRF exch def
  777.  
  778.  
  779.  
  780. % Enter the main program in the current dictionary, most likely userdict.
  781. /make-gsfont { envGSRF begin  make-gsfont  end } bind def
  782.  
  783.  
  784. % If the program was invoked from the command line, run it now.
  785. shellarguments { make-gsfont } if
  786.