]> git.lizzy.rs Git - plan9front.git/blob - sys/lib/ghostscript/pf2afm.ps
aux/cpuid: decode family and model bitfields
[plan9front.git] / sys / lib / ghostscript / pf2afm.ps
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,v 1.8 2005/08/24 17:04:21 raph Exp $
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