%!% This is a PostScript program for making an AFM file from% PFB / PFA and (optionally) PFM files.%% Written in BOP s.c., Gda\'nsk, Poland% e-mail contact: B.Jackowski@GUST.ORG.PL% version 0.5 (18 XII 1997)% version 0.55 (11 III 1998) -- unlimited number of chars in a font% version 1.00 (27 III 1998) -- scanning PFM subdirectory added,% code improved; version sent to LPD% version 1.01 (1 II 2000) -- message changed % Usage:% gs [-dNODISPLAY] -- pf2afm.ps disk_font_name%% The result is written to the file disk_font_name.afm, provided such% a file does not exist; otherwise program quits.%% The font can be either *.pfa or *.pfb; if no extension is supplied,% first disk_font_name.pfb is examined, then disk_font_name.pfa.% Moreover, if there is a *.pfm file in the same directory or in the% subdirectory PFM, i.e., disk_font_name.pfm or PFM/disk_font_name.pfm,% kern pairs from it are extracted, as well as additional font% parameters, usually absent from Type 1 fonts. % Tribute:% The program is based on James Clark's <jjc@jclark.uucp> printafm.ps% (with alterations by d.love@dl.ac.uk and L. Peter Deutsch) from% Ghostscript 5.10 distribution. /onechar 1 string def/edef {exch def} def % charnumber print-charname -% prints the name of the encoded character/print-charname { PFBencoding exch get =string cvs dup (.notdef) eq { /was.notdef true def } if print.to.ofi ( ) print.to.ofi} def /printquit {print flush quit} def % redirecting GS output to ``ofi'' file/eolch (\r\n) def/=only.to.ofi {ofi exch write=only} def % replaces GS's `=only'/print.to.ofi {ofi exch writestring} def % replaces `print'/=to.ofi { =only.to.ofi eolch print.to.ofi } def % replaces `=' % read and skip: byte, short, word, double and long/readb-p {currPFMfile read not {(Unexpected EOF) printquit} if} def/readw-p {readb-p readb-p 256 mul add} def/reads-p {readw-p dup 32768 ge {65536 sub} if} def/readd-p {readb-p readb-p readb-p readb-p 256 mul add 256 mul add 256 mul add} def/readl-p /readd-p load def % double word is, in fact, long integer in GS/skipb-p {readb-p pop} def/skipw-p {skipb-p skipb-p} def/skips-p /skipw-p load def/skipd-p {skipb-p skipb-p skipb-p skipb-p} def/skipl-p /skipd-p load def/skipa-p { {skipb-p} repeat} def % PFMfile readPFMheader -% defines currPFMfile, PFMExtMetricOffset, PFMPairKernTableOffset /readPFMheader { currPFMfile bytesavailable % --------------- % PFM MAIN HEADER % --------------- skipw-p % PFM: version readd-p % PFM: size (size is dword, not word as the documentation says) ne {(Wrong file size) printquit} if 60 skipa-p % PFM: copyright skipw-p % PFM: Type skipw-p % PFM: Points skipw-p % PFM: VertRes skipw-p % PFM: HorizRes skipw-p % PFM: Ascent skipw-p % PFM: InternalLeading skipw-p % PFM: ExternalLeading skipb-p % PFM: Italic skipb-p % PFM: Underline skipb-p % PFM: Stikeout skipw-p % PFM: Weight skipb-p % PFM: CharSet skipw-p % PFM: PixWidth skipw-p % PFM: PixHeight skipb-p % PFM: PitchAndFamily skipw-p % PFM: AvgWidth skipw-p % PFM: MaxWidth skipb-p % PFM: FirstChar skipb-p % PFM: LastChar skipb-p % PFM: DefaultChar skipb-p % PFM: BreakChar skipw-p % PFM: WidthBytes skipd-p % PFM: Device skipd-p % PFM: Face skipd-p % PFM: BitsPointer skipd-p % PFM: BitsOffset % here we assume that it is a PostScript font, i.e., it always uses % the extended width table, therefore the normal width table is empty % ------------- % PFM EXTENSION % ------------- skipw-p % PFMEX: SizeFields readd-p % PFMEX: ExtMetricOffset /PFMExtMetricOffset edef skipd-p % PFMEX: ExtentTable skipd-p % PFMEX: OriginTable readd-p % PFMEX: PairKernTable /PFMPairKernTableOffset edef skipd-p % PFMEX: TrackKernTable skipd-p % PFMEX: DriverInfo skipd-p % PFMEX: Reserved} def % requires that currPFMfile, PFMExtMetricOffset are defined% readPFMExtMetric -% defines PFMNumberofKernPairs /readPFMExtMetric { currPFMfile PFMExtMetricOffset setfileposition skips-p % EXTT: Size skips-p % EXTT: PointSize skips-p % EXTT: Orientation skips-p % EXTT: MasterHeight skips-p % EXTT: MinScale skips-p % EXTT: MaxScale skips-p % EXTT: MasterUnit reads-p % EXTT: CapHeight /PFMCapHeight edef reads-p % EXTT: XHeight /PFMXHeight edef reads-p % EXTT: LowerCaseAscent /PFMLowerCaseAscent edef reads-p % EXTT: LowerCaseDescent neg /PFMLowerCaseDescent edef skips-p % EXTT: Slant skips-p % EXTT: SuperScript skips-p % EXTT: SubScript skips-p % EXTT: SuperScriptSize skips-p % EXTT: SubScriptSize skips-p % EXTT: UnderlineOffset skips-p % EXTT: UnderlineWidth skips-p % EXTT: DoubleUpperUnderlineOffset skips-p % EXTT: DoubleLowerUnderlineOffset skips-p % EXTT: DoubleUpperUnderlineWidth skips-p % EXTT: DoubleLowerUnderlineWidth skips-p % EXTT: StrikeOutOffset skips-p % EXTT: StrikeOutWidth readw-p % EXTT: KernPairs /PFMNumberofKernPairs edef skipw-p % EXTT: KernTracks} def % requires that currPFMfile, PFMPairKernTableOffset, PFMNumberofKernPairs are defined% readPFMExtMetric -% prints kern pairs table in the AFM format /readPFMKernPairs { currPFMfile () ne { PFMdict begin PFMPairKernTableOffset 0 ne { currPFMfile PFMPairKernTableOffset setfileposition readw-p % undocumented kern count (although all remaining structures are % explicitly preceded by their sizes); if it were a stable % feature, EXTTEXTMETRICS could be skipped PFMNumberofKernPairs% 2 copy = = ne { (Inconsistent number of kern pairs) printquit } if (StartKernData) =to.ofi (StartKernPairs ) print.to.ofi PFMNumberofKernPairs =to.ofi % --------- % MAIN LOOP % --------- /was.notdef false def PFMNumberofKernPairs { (KPX ) print.to.ofi readb-p % first char print-charname readb-p % second char print-charname reads-p % kern amount =to.ofi } repeat was.notdef { (.notdef character ocurred among kern pairs) = (you'd better check the resulting AFM file.) = } if (EndKernPairs) =to.ofi (EndKernData) =to.ofi } if end } if} def % alias (for ``compatibility'' with J. Clark):/printkernpairs /readPFMKernPairs load def % printcharmetrics - /printcharmetrics { (StartCharMetrics ) print.to.ofi /PFBencoding currfont /Encoding get dup length array copy def /PFBcharstrings currfont /CharStrings get def PFBcharstrings length PFBcharstrings /.notdef known { 1 sub } if =to.ofi currfont 1000 scalefont setfont % checking Encoding array and CharStrings dictionary for % the consistency of names /was.inconsitent false def 0 1 255 { dup PFBencoding exch get PFBcharstrings exch known { pop }{% dup PFBencoding exch get = PFBencoding exch /.notdef put % fix Encoding array /was.inconsitent true def } ifelse } for was.inconsitent { (Encoding array contains name(s) absent from CharStrings dictionary) = } if % print metric data for each character in PFB encoding vector 0 1 255 { dup PFBencoding exch get dup /.notdef ne { exch dup printmetric }{ pop pop } ifelse } for % xPFBencoding contains an entry for each name in the original % encoding vector /xPFBencoding PFBcharstrings length dict def PFBencoding { xPFBencoding exch true put } forall /fontiter 0 def /TMPFontTemplate (TMP_FONT#000) def { % NewPFBencoding is the new encoding vector /NewPFBencoding 256 array def 0 1 255 { NewPFBencoding exch /.notdef put } for % fill up NewPFBencoding with names from CharStrings dictionary that % are not encoded so far /i 0 def PFBcharstrings { pop i 255 le { dup xPFBencoding exch known not { dup xPFBencoding exch true put NewPFBencoding i 3 -1 roll put /i i 1 add def }{ pop } ifelse }{ pop exit } ifelse } forall i 0 eq {exit} if % define a new font with NewPFBencoding as its encoding vector currfont maxlength dict /NewTMPfont edef currfont { exch dup dup /FID ne exch /Encoding ne and { exch NewTMPfont 3 1 roll put }{ pop pop } ifelse } forall % compute a unique name for a font to be registered /fontiter fontiter 1 add def TMPFontTemplate fontiter (000) cvs dup length TMPFontTemplate length exch sub exch putinterval /TMPFontName TMPFontTemplate cvn def NewTMPfont /FontName TMPFontName put NewTMPfont /Encoding NewPFBencoding put % make this new font the current font TMPFontName NewTMPfont definefont 1000 scalefont setfont % print metric data for each character in the newly created encoding vector 0 1 255 { dup NewPFBencoding exch get dup /.notdef ne { exch -1 printmetric }{ pop pop exit } ifelse } for i 255 lt {exit} if } loop (EndCharMetrics) =to.ofi} def % name actual_code normal_code printmetric - /printmetric { (C ) print.to.ofi =only.to.ofi ( ; WX ) print.to.ofi onechar 0 3 -1 roll put onechar stringwidth pop round cvi =only.to.ofi ( ; N ) print.to.ofi =only.to.ofi ( ; B ) print.to.ofi newpath 0 0 moveto onechar false charpath flattenpath pathbbox newpath round cvi /ury edef round cvi /urx edef round cvi /lly edef round cvi /llx edef ury lly eq {/ury 0 def /lly 0 def} if % normalize degenrated BB urx llx eq {/urx 0 def /llx 0 def} if % llx =only.to.ofi ( ) print.to.ofi lly =only.to.ofi ( ) print.to.ofi urx =only.to.ofi ( ) print.to.ofi ury =only.to.ofi ( ) print.to.ofi (;) =to.ofi} def /printinfoitem { 3 1 roll 2 copy known { get =string cvs exch print.to.ofi ( ) print.to.ofi =to.ofi }{ pop pop pop } ifelse} def /printfontinfo { (Comment AFM Generated by Ghostscript/pf2afm) =to.ofi currfont /FontName (FontName) printinfoitem % currfont /FontInfo get dup /FullName (FullName) printinfoitem dup /FamilyName (FamilyName) printinfoitem dup /Weight (Weight) printinfoitem dup /Notice (Notice) printinfoitem dup /ItalicAngle (ItalicAngle) printinfoitem dup /isFixedPitch (IsFixedPitch) printinfoitem dup /UnderlinePosition (UnderlinePosition) printinfoitem dup /UnderlineThickness (UnderlineThickness) printinfoitem /version (Version) printinfoitem % (EncodingScheme FontSpecific) =to.ofi % (FontBBox) print.to.ofi currfont /FontBBox get { ( ) print.to.ofi round cvi =only.to.ofi } forall eolch print.to.ofi % currPFMfile () ne { PFMdict dup /PFMCapHeight (CapHeight) printinfoitem dup /PFMXHeight (XHeight) printinfoitem dup /PFMLowerCaseDescent (Descender) printinfoitem /PFMLowerCaseAscent (Ascender) printinfoitem } if} def /readPFBfile { % make a shot of the actual font directory: /oldFontDirectory FontDirectory dup length dict copy def isPFB {% defined in `makeafm' (r) file true /PFBDecode filter cvx % true is better (see gs_type1.ps) mark exch exec }{ (r) file mark exch run } ifelse cleartomark % make a shot of the updated font directory: /newFontDirectory FontDirectory dup length dict copy def % spot the added font: oldFontDirectory {pop newFontDirectory exch undef} forall newFontDirectory length 1 ne { newFontDirectory length = (Weird PFB file?) printquit } if newFontDirectory {pop} forall findfont /currfont edef} def /readPFMfile { dup () ne { (r) file /currPFMfile edef 10 dict dup /PFMdict edef begin readPFMheader readPFMExtMetric end }{ pop /currPFMfile () def } ifelse} def % pfmfilename pf[ba]filename filetype printafm -% where filetype=(a) or (b) /printafm { readPFBfile readPFMfile (StartFontMetrics 2.0) =to.ofi printfontinfo printcharmetrics printkernpairs (EndFontMetrics) =to.ofi} def % pf[ba]filename makeafm - /makeafm { count 0 eq {(Missing font file name) printquit} if /ifn edef ifn length 0 eq {(Empty font file name) printquit} if% the following piece of the code does, in fact, the job of a system shell,% i.e., it analyses the supplied names, appends extensions if needed,% and check files: /pfbn () def /pfan () def /pfmn () def % initialisation ifn (.pfb) search { 3 -1 roll length 0 eq {% file name extension = ".pfb" ifn dup length string copy /pfbn edef /ifn edef }{pop} ifelse } if pop ifn (.pfa) search { 3 -1 roll length 0 eq {% file name extension = ".pfa" ifn dup length string copy /pfan edef /ifn edef }{pop} ifelse } if pop pfbn () eq pfan () eq and dup {% no extension was supplied, try ".pfb" /pfbn ifn (.pfb) concatstrings def } if pfbn () ne {% check whether "filename.pfb" exists pfbn status {pop pop pop pop /isPFB true def}{/pfbn () def} ifelse } if pfbn () eq and {% checking "filename.pfb" unsuccessful, try ".pfa" /pfan ifn (.pfa) concatstrings def } if pfan () ne {% check whether "filename.pfa" exists pfan status {pop pop pop pop /isPFB false def}{/pfan () def} ifelse } if pfbn () eq pfan () eq and { (Neither pfa nor pfb found) printquit } if /ofn ifn (.afm) concatstrings def ofn status { pop pop pop pop (Resulting file exists) printquit } if /ofi ofn (w) file def /pfmn ifn (.pfm) concatstrings def pfmn status { pop pop pop pop }{ () pfmn { (/) search { 4 -1 roll exch concatstrings exch concatstrings exch }{ exit } ifelse } loop (pfm/) exch concatstrings concatstrings dup status { pop pop pop pop /pfmn edef }{ pop /pfmn () def (pfm file not found -- ignored) print } ifelse } ifelse pfmn isPFB {pfbn}{pfan} ifelse printafm } def % Check for command line arguments.[ shellarguments { ] dup length 1 eq { 0 get makeafm }{ (This is PF2AFM -- AFM generator \(ver. 1.00\)\n) (Usage: gs [-dNODISPLAY] -- pf2afm.ps disk_font_name\n) printquit } ifelse } {pop}ifelse
%!
% This is a PostScript program for making an AFM file from
% PFB / PFA and (optionally) PFM files.
%
% Written in BOP s.c., Gda\'nsk, Poland
% e-mail contact: B.Jackowski@GUST.ORG.PL
% version 0.5 (18 XII 1997)
% version 0.55 (11 III 1998) -- unlimited number of chars in a font
% version 1.00 (27 III 1998) -- scanning PFM subdirectory added,
% code improved; version sent to LPD
% version 1.01 (1 II 2000) -- message changed
% Usage:
% gs [-dNODISPLAY] -- pf2afm.ps disk_font_name
%
% The result is written to the file disk_font_name.afm, provided such
% a file does not exist; otherwise program quits.
%
% The font can be either *.pfa or *.pfb; if no extension is supplied,
% first disk_font_name.pfb is examined, then disk_font_name.pfa.
% Moreover, if there is a *.pfm file in the same directory or in the
% subdirectory PFM, i.e., disk_font_name.pfm or PFM/disk_font_name.pfm,
% kern pairs from it are extracted, as well as additional font
% parameters, usually absent from Type 1 fonts.
% Tribute:
% The program is based on James Clark's <jjc@jclark.uucp> printafm.ps
% (with alterations by d.love@dl.ac.uk and L. Peter Deutsch) from
% Ghostscript 5.10 distribution.
/onechar 1 string def
/edef {exch def} def
% charnumber print-charname -
% prints the name of the encoded character
/print-charname {
PFBencoding exch get =string cvs dup
(.notdef) eq {
/was.notdef true def
} if
print.to.ofi ( ) print.to.ofi
} def
/printquit {print flush quit} def
% redirecting GS output to ``ofi'' file
/eolch (\r\n) def
/=only.to.ofi {ofi exch write=only} def % replaces GS's `=only'
/print.to.ofi {ofi exch writestring} def % replaces `print'
/=to.ofi { =only.to.ofi eolch print.to.ofi } def % replaces `='
% read and skip: byte, short, word, double and long
/readb-p {currPFMfile read not {(Unexpected EOF) printquit} if} def
/readw-p {readb-p readb-p 256 mul add} def
/reads-p {readw-p dup 32768 ge {65536 sub} if} def
/readd-p {readb-p readb-p readb-p readb-p 256 mul add 256 mul add 256 mul add} def
/readl-p /readd-p load def % double word is, in fact, long integer in GS
/skipb-p {readb-p pop} def
/skipw-p {skipb-p skipb-p} def
/skips-p /skipw-p load def
/skipd-p {skipb-p skipb-p skipb-p skipb-p} def
/skipl-p /skipd-p load def
/skipa-p { {skipb-p} repeat} def
% PFMfile readPFMheader -
% defines currPFMfile, PFMExtMetricOffset, PFMPairKernTableOffset
/readPFMheader {
currPFMfile bytesavailable
% ---------------
% PFM MAIN HEADER
% ---------------
skipw-p % PFM: version
readd-p % PFM: size (size is dword, not word as the documentation says)
ne {(Wrong file size) printquit} if
60 skipa-p % PFM: copyright
skipw-p % PFM: Type
skipw-p % PFM: Points
skipw-p % PFM: VertRes
skipw-p % PFM: HorizRes
skipw-p % PFM: Ascent
skipw-p % PFM: InternalLeading
skipw-p % PFM: ExternalLeading
skipb-p % PFM: Italic
skipb-p % PFM: Underline
skipb-p % PFM: Stikeout
skipw-p % PFM: Weight
skipb-p % PFM: CharSet
skipw-p % PFM: PixWidth
skipw-p % PFM: PixHeight
skipb-p % PFM: PitchAndFamily
skipw-p % PFM: AvgWidth
skipw-p % PFM: MaxWidth
skipb-p % PFM: FirstChar
skipb-p % PFM: LastChar
skipb-p % PFM: DefaultChar
skipb-p % PFM: BreakChar
skipw-p % PFM: WidthBytes
skipd-p % PFM: Device
skipd-p % PFM: Face
skipd-p % PFM: BitsPointer
skipd-p % PFM: BitsOffset
% here we assume that it is a PostScript font, i.e., it always uses
% the extended width table, therefore the normal width table is empty
% -------------
% PFM EXTENSION
% -------------
skipw-p % PFMEX: SizeFields
readd-p % PFMEX: ExtMetricOffset
/PFMExtMetricOffset edef
skipd-p % PFMEX: ExtentTable
skipd-p % PFMEX: OriginTable
readd-p % PFMEX: PairKernTable
/PFMPairKernTableOffset edef
skipd-p % PFMEX: TrackKernTable
skipd-p % PFMEX: DriverInfo
skipd-p % PFMEX: Reserved
} def
% requires that currPFMfile, PFMExtMetricOffset are defined
% readPFMExtMetric -
% defines PFMNumberofKernPairs
/readPFMExtMetric {
currPFMfile PFMExtMetricOffset setfileposition
skips-p % EXTT: Size
skips-p % EXTT: PointSize
skips-p % EXTT: Orientation
skips-p % EXTT: MasterHeight
skips-p % EXTT: MinScale
skips-p % EXTT: MaxScale
skips-p % EXTT: MasterUnit
reads-p % EXTT: CapHeight
/PFMCapHeight edef
reads-p % EXTT: XHeight
/PFMXHeight edef
reads-p % EXTT: LowerCaseAscent
/PFMLowerCaseAscent edef
reads-p % EXTT: LowerCaseDescent
neg /PFMLowerCaseDescent edef
skips-p % EXTT: Slant
skips-p % EXTT: SuperScript
skips-p % EXTT: SubScript
skips-p % EXTT: SuperScriptSize
skips-p % EXTT: SubScriptSize
skips-p % EXTT: UnderlineOffset
skips-p % EXTT: UnderlineWidth
skips-p % EXTT: DoubleUpperUnderlineOffset
skips-p % EXTT: DoubleLowerUnderlineOffset
skips-p % EXTT: DoubleUpperUnderlineWidth
skips-p % EXTT: DoubleLowerUnderlineWidth
skips-p % EXTT: StrikeOutOffset
skips-p % EXTT: StrikeOutWidth
readw-p % EXTT: KernPairs
/PFMNumberofKernPairs edef
skipw-p % EXTT: KernTracks
} def
% requires that currPFMfile, PFMPairKernTableOffset, PFMNumberofKernPairs are defined
% readPFMExtMetric -
% prints kern pairs table in the AFM format
/readPFMKernPairs {
currPFMfile () ne {
PFMdict begin
PFMPairKernTableOffset 0 ne {
currPFMfile PFMPairKernTableOffset setfileposition
readw-p % undocumented kern count (although all remaining structures are
% explicitly preceded by their sizes); if it were a stable
% feature, EXTTEXTMETRICS could be skipped
PFMNumberofKernPairs
% 2 copy = =
ne {
(Inconsistent number of kern pairs) printquit
} if
(StartKernData) =to.ofi
(StartKernPairs ) print.to.ofi
PFMNumberofKernPairs =to.ofi
% ---------
% MAIN LOOP
% ---------
/was.notdef false def
PFMNumberofKernPairs {
(KPX ) print.to.ofi
readb-p % first char
print-charname
readb-p % second char
print-charname
reads-p % kern amount
=to.ofi
} repeat
was.notdef {
(.notdef character ocurred among kern pairs) =
(you'd better check the resulting AFM file.) =
} if
(EndKernPairs) =to.ofi
(EndKernData) =to.ofi
} if
end
} if
} def
% alias (for ``compatibility'' with J. Clark):
/printkernpairs /readPFMKernPairs load def
% printcharmetrics -
/printcharmetrics {
(StartCharMetrics ) print.to.ofi
/PFBencoding currfont /Encoding get dup length array copy def
/PFBcharstrings currfont /CharStrings get def
PFBcharstrings length
PFBcharstrings /.notdef known { 1 sub } if =to.ofi
currfont 1000 scalefont setfont
% checking Encoding array and CharStrings dictionary for
% the consistency of names
/was.inconsitent false def
0 1 255 {
dup PFBencoding exch get
PFBcharstrings exch known {
pop
}{
% dup PFBencoding exch get =
PFBencoding exch /.notdef put % fix Encoding array
/was.inconsitent true def
} ifelse
} for
was.inconsitent {
(Encoding array contains name(s) absent from CharStrings dictionary) =
} if
% print metric data for each character in PFB encoding vector
0 1 255 {
dup PFBencoding exch get
dup /.notdef ne {
exch dup printmetric
}{
pop pop
} ifelse
} for
% xPFBencoding contains an entry for each name in the original
% encoding vector
/xPFBencoding PFBcharstrings length dict def
PFBencoding {
xPFBencoding exch true put
} forall
/fontiter 0 def
/TMPFontTemplate (TMP_FONT#000) def
{
% NewPFBencoding is the new encoding vector
/NewPFBencoding 256 array def
0 1 255 {
NewPFBencoding exch /.notdef put
} for
% fill up NewPFBencoding with names from CharStrings dictionary that
% are not encoded so far
/i 0 def
PFBcharstrings {
pop
i 255 le {
dup xPFBencoding exch known not {
dup xPFBencoding exch true put
NewPFBencoding i 3 -1 roll put
/i i 1 add def
}{
pop
} ifelse
}{
pop exit
} ifelse
} forall
i 0 eq {exit} if
% define a new font with NewPFBencoding as its encoding vector
currfont maxlength dict /NewTMPfont edef
currfont {
exch dup dup /FID ne exch /Encoding ne and {
exch NewTMPfont 3 1 roll put
}{
pop pop
} ifelse
} forall
% compute a unique name for a font to be registered
/fontiter fontiter 1 add def
TMPFontTemplate fontiter (000) cvs
dup length TMPFontTemplate length exch sub exch putinterval
/TMPFontName TMPFontTemplate cvn def
NewTMPfont /FontName TMPFontName put
NewTMPfont /Encoding NewPFBencoding put
% make this new font the current font
TMPFontName NewTMPfont definefont 1000 scalefont setfont
% print metric data for each character in the newly created encoding vector
0 1 255 {
dup NewPFBencoding exch get
dup /.notdef ne {
exch -1 printmetric
}{
pop pop exit
} ifelse
} for
i 255 lt {exit} if
} loop
(EndCharMetrics) =to.ofi
} def
% name actual_code normal_code printmetric -
/printmetric {
(C ) print.to.ofi =only.to.ofi
( ; WX ) print.to.ofi
onechar 0 3 -1 roll put
onechar stringwidth pop round cvi =only.to.ofi
( ; N ) print.to.ofi =only.to.ofi
( ; B ) print.to.ofi
newpath 0 0 moveto
onechar false charpath flattenpath pathbbox
newpath
round cvi /ury edef round cvi /urx edef
round cvi /lly edef round cvi /llx edef
ury lly eq {/ury 0 def /lly 0 def} if % normalize degenrated BB
urx llx eq {/urx 0 def /llx 0 def} if %
llx =only.to.ofi ( ) print.to.ofi lly =only.to.ofi ( ) print.to.ofi
urx =only.to.ofi ( ) print.to.ofi ury =only.to.ofi ( ) print.to.ofi
(;) =to.ofi
} def
/printinfoitem {
3 1 roll 2 copy known {
get =string cvs exch
print.to.ofi ( ) print.to.ofi =to.ofi
}{
pop pop pop
} ifelse
} def
/printfontinfo {
(Comment AFM Generated by Ghostscript/pf2afm) =to.ofi
currfont /FontName (FontName) printinfoitem
%
currfont /FontInfo get
dup /FullName (FullName) printinfoitem
dup /FamilyName (FamilyName) printinfoitem
dup /Weight (Weight) printinfoitem
dup /Notice (Notice) printinfoitem
dup /ItalicAngle (ItalicAngle) printinfoitem
dup /isFixedPitch (IsFixedPitch) printinfoitem
dup /UnderlinePosition (UnderlinePosition) printinfoitem
dup /UnderlineThickness (UnderlineThickness) printinfoitem
/version (Version) printinfoitem
%
(EncodingScheme FontSpecific) =to.ofi
%
(FontBBox) print.to.ofi
currfont /FontBBox get {
( ) print.to.ofi round cvi =only.to.ofi
} forall
eolch print.to.ofi
%
currPFMfile () ne {
PFMdict
dup /PFMCapHeight (CapHeight) printinfoitem
dup /PFMXHeight (XHeight) printinfoitem
dup /PFMLowerCaseDescent (Descender) printinfoitem
/PFMLowerCaseAscent (Ascender) printinfoitem
} if
} def
/readPFBfile {
% make a shot of the actual font directory:
/oldFontDirectory FontDirectory dup length dict copy def
isPFB {% defined in `makeafm'
(r) file true /PFBDecode filter cvx % true is better (see gs_type1.ps)
mark exch exec
}{
(r) file mark exch run
} ifelse
cleartomark
% make a shot of the updated font directory:
/newFontDirectory FontDirectory dup length dict copy def
% spot the added font:
oldFontDirectory {pop newFontDirectory exch undef} forall
newFontDirectory length 1 ne {
newFontDirectory length =
(Weird PFB file?) printquit
} if
newFontDirectory {pop} forall
findfont /currfont edef
} def
/readPFMfile {
dup () ne {
(r) file /currPFMfile edef
10 dict dup /PFMdict edef begin
readPFMheader
readPFMExtMetric
end
}{
pop /currPFMfile () def
} ifelse
} def
% pfmfilename pf[ba]filename filetype printafm -
% where filetype=(a) or (b)
/printafm {
readPFBfile
readPFMfile
(StartFontMetrics 2.0) =to.ofi
printfontinfo
printcharmetrics
printkernpairs
(EndFontMetrics) =to.ofi
} def
% pf[ba]filename makeafm -
/makeafm {
count 0 eq {(Missing font file name) printquit} if
/ifn edef
ifn length 0 eq {(Empty font file name) printquit} if
% the following piece of the code does, in fact, the job of a system shell,
% i.e., it analyses the supplied names, appends extensions if needed,
% and check files:
/pfbn () def /pfan () def /pfmn () def % initialisation
ifn (.pfb) search {
3 -1 roll length 0 eq {% file name extension = ".pfb"
ifn dup length string copy /pfbn edef
/ifn edef
}{pop} ifelse
} if pop
ifn (.pfa) search {
3 -1 roll length 0 eq {% file name extension = ".pfa"
ifn dup length string copy /pfan edef
/ifn edef
}{pop} ifelse
} if pop
pfbn () eq pfan () eq and dup {% no extension was supplied, try ".pfb"
/pfbn ifn (.pfb) concatstrings def
} if
pfbn () ne {% check whether "filename.pfb" exists
pfbn status {pop pop pop pop /isPFB true def}{/pfbn () def} ifelse
} if
pfbn () eq and {% checking "filename.pfb" unsuccessful, try ".pfa"
/pfan ifn (.pfa) concatstrings def
} if
pfan () ne {% check whether "filename.pfa" exists
pfan status {pop pop pop pop /isPFB false def}{/pfan () def} ifelse
} if
pfbn () eq pfan () eq and {
(Neither pfa nor pfb found) printquit
} if
/ofn ifn (.afm) concatstrings def
ofn status {
pop pop pop pop (Resulting file exists) printquit
} if
/ofi ofn (w) file def
/pfmn ifn (.pfm) concatstrings def
pfmn status {
pop pop pop pop
}{
() pfmn {
(/) search {
4 -1 roll exch concatstrings exch concatstrings exch
}{
exit
} ifelse
} loop
(pfm/) exch concatstrings concatstrings
dup status {
pop pop pop pop /pfmn edef
}{
pop /pfmn () def (pfm file not found -- ignored) print
} ifelse
} ifelse
pfmn
isPFB {pfbn}{pfan} ifelse
printafm
} def
% Check for command line arguments.
[ shellarguments
{ ] dup length 1 eq {
0 get makeafm
}{
(This is PF2AFM -- AFM generator \(ver. 1.00\)\n)
(Usage: gs [-dNODISPLAY] -- pf2afm.ps disk_font_name\n) printquit
} ifelse
}
{pop}
ifelse