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

  1. %!
  2. % This is a PostScript program for making an AFM file from
  3. % PFB / PFA and (optionally) PFM files.
  4. %
  5. % Written in BOP s.c., Gda\'nsk, Poland
  6. % e-mail contact: B.Jackowski@GUST.ORG.PL
  7. % version 0.5 (18 XII 1997)
  8. % version 0.55 (11 III 1998) -- unlimited number of chars in a font
  9. % version 1.00 (27 III 1998) -- scanning PFM subdirectory added,
  10. %                               code improved; version sent to LPD
  11. % version 1.01 (1 II 2000)   -- message changed
  12.  
  13. % Usage:
  14. %   gs [-dNODISPLAY] -- pf2afm.ps disk_font_name
  15. %
  16. % The result is written to the file disk_font_name.afm, provided such
  17. % a file does not exist; otherwise program quits.
  18. %
  19. % The font can be either *.pfa or *.pfb; if no extension is supplied,
  20. % first disk_font_name.pfb is examined, then disk_font_name.pfa.
  21. % Moreover, if there is a *.pfm file in the same directory or in the
  22. % subdirectory PFM, i.e., disk_font_name.pfm or PFM/disk_font_name.pfm,
  23. % kern pairs from it are extracted, as well as additional font
  24. % parameters, usually absent from Type 1 fonts.
  25.  
  26. % Tribute:
  27. % The program is based on James Clark's <jjc@jclark.uucp> printafm.ps
  28. % (with alterations by d.love@dl.ac.uk and L. Peter Deutsch) from
  29. % Ghostscript 5.10 distribution.
  30.  
  31. /onechar 1 string def
  32. /edef {exch def} def
  33.  
  34. % charnumber print-charname -
  35. % prints the name of the encoded character
  36. /print-charname {
  37.   PFBencoding exch get =string cvs dup
  38.   (.notdef) eq {
  39.     /was.notdef true def
  40.   } if
  41.   print.to.ofi ( ) print.to.ofi
  42. } def
  43.  
  44. /printquit {print flush quit} def
  45.  
  46. % redirecting GS output to ``ofi'' file
  47. /eolch (\r\n) def
  48. /=only.to.ofi {ofi exch write=only} def          % replaces GS's `=only'
  49. /print.to.ofi  {ofi exch writestring} def        % replaces `print'
  50. /=to.ofi { =only.to.ofi eolch print.to.ofi } def % replaces `='
  51.  
  52. % read and skip: byte, short, word, double and long
  53. /readb-p {currPFMfile read not {(Unexpected EOF) printquit} if} def
  54. /readw-p {readb-p readb-p 256 mul add} def
  55. /reads-p {readw-p dup 32768 ge {65536 sub} if} def
  56. /readd-p {readb-p readb-p readb-p readb-p 256 mul add 256 mul add 256 mul add} def
  57. /readl-p /readd-p load def % double word is, in fact, long integer in GS
  58. /skipb-p {readb-p pop} def
  59. /skipw-p {skipb-p skipb-p} def
  60. /skips-p /skipw-p load def
  61. /skipd-p {skipb-p skipb-p skipb-p skipb-p} def
  62. /skipl-p /skipd-p load def
  63. /skipa-p { {skipb-p} repeat} def
  64.  
  65. % PFMfile readPFMheader -
  66. % defines currPFMfile, PFMExtMetricOffset, PFMPairKernTableOffset
  67.  
  68. /readPFMheader {
  69.   currPFMfile bytesavailable
  70.   % ---------------
  71.   % PFM MAIN HEADER
  72.   % ---------------
  73.   skipw-p % PFM: version
  74.   readd-p % PFM: size (size is dword, not word as the documentation says)
  75.   ne {(Wrong file size) printquit} if
  76.   60 skipa-p  % PFM: copyright
  77.   skipw-p % PFM: Type
  78.   skipw-p % PFM: Points
  79.   skipw-p % PFM: VertRes
  80.   skipw-p % PFM: HorizRes
  81.   skipw-p % PFM: Ascent
  82.   skipw-p % PFM: InternalLeading
  83.   skipw-p % PFM: ExternalLeading
  84.   skipb-p % PFM: Italic
  85.   skipb-p % PFM: Underline
  86.   skipb-p % PFM: Stikeout
  87.   skipw-p % PFM: Weight
  88.   skipb-p % PFM: CharSet
  89.   skipw-p % PFM: PixWidth
  90.   skipw-p % PFM: PixHeight
  91.   skipb-p % PFM: PitchAndFamily
  92.   skipw-p % PFM: AvgWidth
  93.   skipw-p % PFM: MaxWidth
  94.   skipb-p % PFM: FirstChar
  95.   skipb-p % PFM: LastChar
  96.   skipb-p % PFM: DefaultChar
  97.   skipb-p % PFM: BreakChar
  98.   skipw-p % PFM: WidthBytes
  99.   skipd-p % PFM: Device
  100.   skipd-p % PFM: Face
  101.   skipd-p % PFM: BitsPointer
  102.   skipd-p % PFM: BitsOffset
  103.   % here we assume that it is a PostScript font, i.e., it always uses
  104.   % the extended width table, therefore the normal width table is empty
  105.   % -------------
  106.   % PFM EXTENSION
  107.   % -------------
  108.   skipw-p % PFMEX: SizeFields
  109.   readd-p % PFMEX: ExtMetricOffset
  110.     /PFMExtMetricOffset edef
  111.   skipd-p % PFMEX: ExtentTable
  112.   skipd-p % PFMEX: OriginTable
  113.   readd-p % PFMEX: PairKernTable
  114.     /PFMPairKernTableOffset edef
  115.   skipd-p % PFMEX: TrackKernTable
  116.   skipd-p % PFMEX: DriverInfo
  117.   skipd-p % PFMEX: Reserved
  118. } def
  119.  
  120. % requires that currPFMfile, PFMExtMetricOffset are defined
  121. % readPFMExtMetric -
  122. % defines PFMNumberofKernPairs
  123.  
  124. /readPFMExtMetric {
  125.   currPFMfile PFMExtMetricOffset setfileposition
  126.   skips-p % EXTT: Size
  127.   skips-p % EXTT: PointSize
  128.   skips-p % EXTT: Orientation
  129.   skips-p % EXTT: MasterHeight
  130.   skips-p % EXTT: MinScale
  131.   skips-p % EXTT: MaxScale
  132.   skips-p % EXTT: MasterUnit
  133.   reads-p % EXTT: CapHeight
  134.    /PFMCapHeight edef
  135.   reads-p % EXTT: XHeight
  136.    /PFMXHeight edef
  137.   reads-p % EXTT: LowerCaseAscent
  138.    /PFMLowerCaseAscent edef
  139.   reads-p % EXTT: LowerCaseDescent
  140.    neg /PFMLowerCaseDescent edef
  141.   skips-p % EXTT: Slant
  142.   skips-p % EXTT: SuperScript
  143.   skips-p % EXTT: SubScript
  144.   skips-p % EXTT: SuperScriptSize
  145.   skips-p % EXTT: SubScriptSize
  146.   skips-p % EXTT: UnderlineOffset
  147.   skips-p % EXTT: UnderlineWidth
  148.   skips-p % EXTT: DoubleUpperUnderlineOffset
  149.   skips-p % EXTT: DoubleLowerUnderlineOffset
  150.   skips-p % EXTT: DoubleUpperUnderlineWidth
  151.   skips-p % EXTT: DoubleLowerUnderlineWidth
  152.   skips-p % EXTT: StrikeOutOffset
  153.   skips-p % EXTT: StrikeOutWidth
  154.   readw-p % EXTT: KernPairs
  155.     /PFMNumberofKernPairs edef
  156.   skipw-p % EXTT: KernTracks
  157. } def
  158.  
  159. % requires that currPFMfile, PFMPairKernTableOffset, PFMNumberofKernPairs are defined
  160. % readPFMExtMetric -
  161. % prints kern pairs table in the AFM format
  162.  
  163. /readPFMKernPairs {
  164.   currPFMfile () ne {
  165.     PFMdict begin
  166.     PFMPairKernTableOffset 0 ne {
  167.       currPFMfile PFMPairKernTableOffset setfileposition
  168.       readw-p % undocumented kern count (although all remaining structures are
  169.               % explicitly preceded by their sizes); if it were a stable
  170.              % feature, EXTTEXTMETRICS could be skipped
  171.       PFMNumberofKernPairs
  172. %     2 copy = =
  173.       ne {
  174.         (Inconsistent number of kern pairs) printquit
  175.       } if
  176.       (StartKernData) =to.ofi
  177.       (StartKernPairs ) print.to.ofi
  178.       PFMNumberofKernPairs =to.ofi
  179.       % ---------
  180.       % MAIN LOOP
  181.       % ---------
  182.       /was.notdef false def
  183.       PFMNumberofKernPairs {
  184.         (KPX ) print.to.ofi
  185.         readb-p  % first  char
  186.         print-charname
  187.         readb-p  % second char
  188.         print-charname
  189.         reads-p  % kern amount
  190.         =to.ofi
  191.       } repeat
  192.       was.notdef {
  193.         (.notdef character ocurred among kern pairs) =
  194.         (you'd better check the resulting AFM file.) =
  195.       } if
  196.       (EndKernPairs) =to.ofi
  197.       (EndKernData)  =to.ofi
  198.     } if
  199.     end
  200.   } if
  201. } def
  202.  
  203. % alias (for ``compatibility'' with J. Clark):
  204. /printkernpairs /readPFMKernPairs load def
  205.  
  206. % printcharmetrics -
  207.  
  208. /printcharmetrics {
  209.   (StartCharMetrics ) print.to.ofi
  210.   /PFBencoding currfont /Encoding get dup length array copy def
  211.   /PFBcharstrings currfont /CharStrings get def
  212.   PFBcharstrings length
  213.   PFBcharstrings /.notdef known { 1 sub } if =to.ofi
  214.   currfont 1000 scalefont setfont
  215.   % checking Encoding array and CharStrings dictionary for
  216.   % the consistency of names
  217.   /was.inconsitent false def
  218.   0 1 255 {
  219.     dup PFBencoding exch get
  220.     PFBcharstrings exch known {
  221.       pop
  222.     }{
  223. %     dup PFBencoding exch get =
  224.       PFBencoding exch /.notdef put % fix Encoding array
  225.       /was.inconsitent true def
  226.     } ifelse
  227.   } for
  228.   was.inconsitent {
  229.     (Encoding array contains name(s) absent from CharStrings dictionary) =
  230.   } if
  231.   % print metric data for each character in PFB encoding vector
  232.   0 1 255 {
  233.     dup PFBencoding exch get
  234.     dup /.notdef ne {
  235.       exch dup printmetric
  236.     }{
  237.       pop pop
  238.     } ifelse
  239.   } for
  240.   % xPFBencoding contains an entry for each name in the original
  241.   % encoding vector
  242.   /xPFBencoding PFBcharstrings length dict def
  243.   PFBencoding {
  244.     xPFBencoding exch true put
  245.   } forall
  246.  
  247.   /fontiter 0 def
  248.   /TMPFontTemplate (TMP_FONT#000) def
  249.   {
  250.     % NewPFBencoding is the new encoding vector
  251.     /NewPFBencoding 256 array def
  252.     0 1 255 {
  253.       NewPFBencoding exch /.notdef put
  254.     } for
  255.     % fill up NewPFBencoding with names from CharStrings dictionary that
  256.     % are not encoded so far
  257.     /i 0 def
  258.     PFBcharstrings {
  259.       pop
  260.       i 255 le {
  261.         dup xPFBencoding exch known not {
  262.           dup xPFBencoding exch true put
  263.           NewPFBencoding i 3 -1 roll put
  264.           /i i 1 add def
  265.         }{
  266.           pop
  267.         } ifelse
  268.       }{
  269.         pop exit
  270.       } ifelse
  271.     } forall
  272.     i 0 eq {exit} if
  273.     % define a new font with NewPFBencoding as its encoding vector
  274.     currfont maxlength dict /NewTMPfont edef
  275.     currfont {
  276.       exch dup dup /FID ne exch /Encoding ne and {
  277.         exch NewTMPfont 3 1 roll put
  278.       }{
  279.         pop pop
  280.       } ifelse
  281.     } forall
  282.     % compute a unique name for a font to be registered
  283.     /fontiter fontiter 1 add def
  284.     TMPFontTemplate fontiter (000) cvs
  285.     dup length TMPFontTemplate length exch sub exch putinterval
  286.     /TMPFontName TMPFontTemplate cvn def
  287.     NewTMPfont /FontName TMPFontName put
  288.     NewTMPfont /Encoding NewPFBencoding put
  289.     % make this new font the current font
  290.     TMPFontName NewTMPfont definefont 1000 scalefont setfont
  291.     % print metric data for each character in the newly created encoding vector
  292.     0 1 255 {
  293.       dup NewPFBencoding exch get
  294.       dup /.notdef ne {
  295.         exch -1 printmetric
  296.       }{
  297.         pop pop exit
  298.       } ifelse
  299.     } for
  300.   i 255 lt {exit} if
  301.   } loop
  302.   (EndCharMetrics) =to.ofi
  303. } def
  304.  
  305. % name actual_code normal_code printmetric -
  306.  
  307. /printmetric {
  308.   (C ) print.to.ofi =only.to.ofi
  309.   ( ; WX ) print.to.ofi
  310.   onechar 0 3 -1 roll put
  311.   onechar stringwidth pop round cvi =only.to.ofi
  312.   ( ; N ) print.to.ofi =only.to.ofi
  313.   ( ; B ) print.to.ofi
  314.   newpath 0 0 moveto
  315.   onechar false charpath flattenpath pathbbox
  316.   newpath
  317.   round cvi /ury edef round cvi /urx edef
  318.   round cvi /lly edef round cvi /llx edef
  319.   ury lly eq {/ury 0 def /lly 0 def} if % normalize degenrated BB
  320.   urx llx eq {/urx 0 def /llx 0 def} if %
  321.   llx =only.to.ofi ( ) print.to.ofi lly =only.to.ofi ( ) print.to.ofi
  322.   urx =only.to.ofi ( ) print.to.ofi ury =only.to.ofi ( ) print.to.ofi
  323.   (;) =to.ofi
  324. } def
  325.  
  326. /printinfoitem {
  327.   3 1 roll 2 copy known {
  328.     get =string cvs exch
  329.     print.to.ofi ( ) print.to.ofi =to.ofi
  330.   }{
  331.     pop pop pop
  332.   } ifelse
  333. } def
  334.  
  335. /printfontinfo {
  336.   (Comment AFM Generated by Ghostscript/pf2afm) =to.ofi
  337.   currfont /FontName  (FontName) printinfoitem
  338.   %
  339.   currfont /FontInfo get
  340.   dup /FullName           (FullName)           printinfoitem
  341.   dup /FamilyName         (FamilyName)         printinfoitem
  342.   dup /Weight             (Weight)             printinfoitem
  343.   dup /Notice             (Notice)             printinfoitem
  344.   dup /ItalicAngle        (ItalicAngle)        printinfoitem
  345.   dup /isFixedPitch       (IsFixedPitch)       printinfoitem
  346.   dup /UnderlinePosition  (UnderlinePosition)  printinfoitem
  347.   dup /UnderlineThickness (UnderlineThickness) printinfoitem
  348.       /version            (Version)            printinfoitem
  349.   %
  350.   (EncodingScheme FontSpecific) =to.ofi
  351.   %
  352.   (FontBBox) print.to.ofi
  353.   currfont /FontBBox get {
  354.     ( ) print.to.ofi round cvi =only.to.ofi
  355.   } forall
  356.   eolch print.to.ofi
  357.   %
  358.   currPFMfile () ne {
  359.     PFMdict
  360.     dup /PFMCapHeight        (CapHeight) printinfoitem
  361.     dup /PFMXHeight          (XHeight)   printinfoitem
  362.     dup /PFMLowerCaseDescent (Descender) printinfoitem
  363.         /PFMLowerCaseAscent  (Ascender)  printinfoitem
  364.   } if
  365. } def
  366.  
  367. /readPFBfile {
  368.   % make a shot of the actual font directory:
  369.   /oldFontDirectory FontDirectory dup length dict copy def
  370.   isPFB {% defined in `makeafm'
  371.     (r) file true /PFBDecode filter cvx % true is better (see gs_type1.ps)
  372.     mark exch exec
  373.   }{
  374.     (r) file mark exch run
  375.   } ifelse
  376.   cleartomark
  377.   % make a shot of the updated font directory:
  378.   /newFontDirectory FontDirectory dup length dict copy def
  379.   % spot the added font:
  380.   oldFontDirectory  {pop newFontDirectory exch undef} forall
  381.   newFontDirectory length 1 ne {
  382.     newFontDirectory length =
  383.     (Weird PFB file?) printquit
  384.   } if
  385.   newFontDirectory {pop} forall
  386.   findfont /currfont edef
  387. } def
  388.  
  389. /readPFMfile {
  390.   dup () ne {
  391.     (r) file /currPFMfile edef
  392.     10 dict dup /PFMdict edef begin
  393.     readPFMheader
  394.     readPFMExtMetric
  395.     end
  396.   }{
  397.     pop /currPFMfile () def
  398.   } ifelse
  399. } def
  400.  
  401. % pfmfilename pf[ba]filename filetype printafm -
  402. % where filetype=(a) or (b)
  403.  
  404. /printafm {
  405.   readPFBfile
  406.   readPFMfile
  407.   (StartFontMetrics 2.0) =to.ofi
  408.   printfontinfo
  409.   printcharmetrics
  410.   printkernpairs
  411.   (EndFontMetrics) =to.ofi
  412. } def
  413.  
  414. % pf[ba]filename makeafm -
  415.  
  416. /makeafm {
  417.   count 0 eq {(Missing font file name) printquit} if
  418.   /ifn edef
  419.   ifn length 0 eq {(Empty font file name) printquit} if
  420. % the following piece of the code does, in fact, the job of a system shell,
  421. % i.e., it analyses the supplied names, appends extensions if needed,
  422. % and check files:
  423.   /pfbn () def /pfan () def /pfmn () def % initialisation
  424.   ifn (.pfb) search {
  425.     3 -1 roll length 0 eq {% file name extension = ".pfb"
  426.       ifn dup length string copy /pfbn edef
  427.       /ifn edef
  428.     }{pop} ifelse
  429.   } if pop
  430.   ifn (.pfa) search {
  431.     3 -1 roll length 0 eq {% file name extension = ".pfa"
  432.       ifn dup length string copy /pfan edef
  433.       /ifn edef
  434.     }{pop} ifelse
  435.   } if pop
  436.   pfbn () eq pfan () eq and dup {% no extension was supplied, try ".pfb"
  437.     /pfbn ifn (.pfb) concatstrings def
  438.   } if
  439.   pfbn () ne {% check whether "filename.pfb" exists
  440.     pfbn status {pop pop pop pop /isPFB true def}{/pfbn () def} ifelse
  441.   } if
  442.   pfbn () eq and {% checking "filename.pfb" unsuccessful, try ".pfa"
  443.     /pfan ifn (.pfa) concatstrings def
  444.   } if
  445.   pfan () ne {% check whether "filename.pfa" exists
  446.     pfan status {pop pop pop pop /isPFB false def}{/pfan () def} ifelse
  447.   } if
  448.  
  449.   pfbn () eq pfan () eq and {
  450.     (Neither pfa nor pfb found) printquit
  451.   } if
  452.  
  453.   /ofn ifn (.afm) concatstrings def
  454.   ofn status {
  455.     pop pop pop pop (Resulting file exists) printquit
  456.   } if
  457.   /ofi ofn (w) file def
  458.  
  459.   /pfmn ifn (.pfm) concatstrings def
  460.   pfmn status {
  461.     pop pop pop pop
  462.   }{
  463.     () pfmn {
  464.       (/) search {
  465.         4 -1 roll exch concatstrings exch concatstrings exch
  466.       }{
  467.         exit
  468.       } ifelse
  469.     } loop
  470.     (pfm/) exch concatstrings concatstrings
  471.     dup status {
  472.       pop pop pop pop /pfmn edef
  473.     }{
  474.       pop /pfmn () def (pfm file not found -- ignored) print
  475.     } ifelse
  476.   } ifelse
  477.  
  478.   pfmn
  479.   isPFB {pfbn}{pfan} ifelse
  480.   printafm
  481.  
  482. } def
  483.  
  484. % Check for command line arguments.
  485. [ shellarguments
  486.   { ] dup length 1 eq {
  487.        0 get makeafm
  488.      }{
  489.        (This is PF2AFM -- AFM generator \(ver. 1.00\)\n)
  490.        (Usage: gs [-dNODISPLAY] -- pf2afm.ps disk_font_name\n) printquit
  491.      } ifelse
  492.   }
  493.   {pop}
  494. ifelse
  495.