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