Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
%    Copyright (C) 1990, 1995, 1996 Aladdin Enterprises.  All rights reserved.
2
% 
3
% This software is provided AS-IS with no warranty, either express or
4
% implied.
5
% 
6
% This software is distributed under license and may not be copied,
7
% modified or distributed except as expressly authorized under the terms
8
% of the license contained in the file LICENSE in this distribution.
9
% 
10
% For more information about licensing, please refer to
11
% http://www.ghostscript.com/licensing/. For information on
12
% commercial licensing, go to http://www.artifex.com/licensing/ or
13
% contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14
% San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15
 
16
% $Id: bdftops.ps,v 1.7 2003/08/06 17:05:09 alexcher Exp $
17
% bdftops.ps
18
% Convert a BDF file (possibly with (an) associated AFM file(s))
19
% to a PostScript Type 1 font (without eexec encryption).
20
% The resulting font will work with any PostScript language interpreter,
21
% but not with ATM or other font rasterizers lacking a complete interpreter.
22
 
23
/envBDF 120 dict def
24
envBDF begin
25
 
26
% "Import" the image-to-path package.
27
% This also brings in the Type 1 opcodes (type1ops.ps).
28
   (impath.ps) runlibfile
29
 
30
% "Import" the font-writing package.
31
   (wrfont.ps) runlibfile
32
   wrfont_dict begin
33
     /binary_CharStrings false def
34
     /binary_tokens false def
35
     /encrypt_CharStrings true def
36
     /standard_only true def
37
   end
38
   /lenIV 0 def
39
 
40
% Invert the StandardEncoding vector.
41
   256 dict dup begin
42
 
43
   end /StandardDecoding exch def
44
 
45
% Define the properties copied to FontInfo.
46
   mark
47
     (COPYRIGHT) /Notice
48
     (FAMILY_NAME) /FamilyName
49
     (FULL_NAME) /FullName
50
     (WEIGHT_NAME) /Weight
51
   .dicttomark /properties exch def
52
 
53
% Define the character sequences for synthesizing missing composite
54
% characters in the standard encoding.
55
   mark
56
     /AE [/A /E]
57
     /OE [/O /E]
58
     /ae [/a /e]
59
     /ellipsis [/period /period /period]
60
     /emdash [/hyphen /hyphen /hyphen]
61
     /endash [/hyphen /hyphen]
62
     /fi [/f /i]
63
     /fl [/f /l]
64
     /germandbls [/s /s]
65
     /guillemotleft [/less /less]
66
     /guillemotright [/greater /greater]
67
     /oe [/o /e]
68
     /quotedblbase [/comma /comma]
69
   .dicttomark /composites exch def
70
 
71
% Define the procedure for synthesizing composites.
72
% This must not be bound.
73
   /compose
74
    { exch pop
75
      FontMatrix Private /composematrix get invertmatrix concat
76
 
77
      dup gsave false charpath pathbbox currentpoint grestore
78
      6 2 roll setcachedevice show
79
    } def
80
% Define the CharString procedure that calls compose, with the string
81
% on the stack.  This too must remain unbound.
82
   /compose_proc
83
    { Private /compose get exec
84
    } def
85
 
86
% Define aliases for missing characters similarly.
87
   mark
88
     /acute /quoteright
89
     /bullet /asterisk
90
     /cedilla /comma
91
     /circumflex /asciicircum
92
     /dieresis /quotedbl
93
     /dotlessi /i
94
     /exclamdown /exclam
95
     /florin /f
96
     /fraction /slash
97
     /grave /quoteleft
98
     /guilsinglleft /less
99
     /guilsinglright /greater
100
     /hungarumlaut /quotedbl
101
     /periodcentered /asterisk
102
     /questiondown /question
103
     /quotedblleft /quotedbl
104
     /quotedblright /quotedbl
105
     /quotesinglbase /comma
106
     /quotesingle /quoteright
107
     /tilde /asciitilde
108
   .dicttomark /aliases exch def
109
 
110
% Define overstruck characters that can be synthesized with seac.
111
   mark
112
    [ /Aacute /Acircumflex /Adieresis /Agrave /Aring /Atilde
113
      /Ccedilla
114
      /Eacute /Ecircumflex /Edieresis /Egrave
115
      /Iacute /Icircumflex /Idieresis /Igrave
116
      /Lslash
117
      /Ntilde
118
      /Oacute /Ocircumflex /Odieresis /Ograve /Otilde
119
      /Scaron
120
      /Uacute /Ucircumflex /Udieresis /Ugrave
121
      /Yacute /Ydieresis
122
      /Zcaron
123
      /aacute /acircumflex /adieresis /agrave /aring /atilde
124
      /ccedilla
125
      /eacute /ecircumflex /edieresis /egrave
126
      /iacute /icircumflex /idieresis /igrave
127
      /lslash
128
      /ntilde
129
      /oacute /ocircumflex /odieresis /ograve /otilde
130
      /scaron
131
      /uacute /ucircumflex /udieresis /ugrave
132
      /yacute /ydieresis
133
      /zcaron
134
    ]
135
    { dup =string cvs
136
      [ exch dup 0 1 getinterval cvn
137
	exch dup length 1 sub 1 exch getinterval cvn
138
      ]
139
    } forall
140
     /cent [/c /slash]
141
     /daggerdbl [/bar /equal]
142
     /divide [/colon /hyphen]
143
     /sterling [/L /hyphen]
144
     /yen [/Y /equal]
145
   .dicttomark /accentedchars exch def
146
 
147
% ------ Output utilities ------ %
148
 
149
   /ws {psfile exch writestring} bind def
150
   /wl {ws (\n) ws} bind def
151
   /wt {=string cvs ws ( ) ws} bind def
152
 
153
% ------ BDF file parsing utilities ------ %
154
 
155
% Define a buffer for reading the BDF file.
156
   /buffer 400 string def
157
 
158
% Read a line from the BDF file into the buffer.
159
% Ignore empty (zero-length) lines.
160
% Define /keyword as the first word on the line.
161
% Define /args as the remainder of the line.
162
% If the keyword is equal to commentword, skip the line.
163
% (If commentword is equal to a space, never skip.)
164
   /nextline
165
    {  { bdfile buffer readline not
166
	  { (Premature EOF\n) print stop } if
167
	 dup length 0 ne { exit } if pop	 
168
       }
169
      loop
170
      ( ) search
171
       { /keyword exch def pop }
172
       { /keyword exch def () }
173
      ifelse
174
      /args exch def
175
      keyword commentword eq { nextline } if
176
    } bind def
177
 
178
% Get a word argument from args.  We do *not* copy the string.
179
   /warg		% warg -> string
180
    { args ( ) search
181
       { exch pop exch }
182
       { () }
183
      ifelse  /args exch def
184
    } bind def
185
 
186
% Get an integer argument from args.
187
   /iarg		% iarg -> int
188
    { warg cvi
189
    } bind def
190
 
191
% Get a numeric argument from args.
192
   /narg		% narg -> int|real
193
    { warg cvr
194
      dup dup cvi eq { cvi } if
195
    } bind def
196
 
197
% Convert the remainder of args into a string.
198
   /remarg		% remarg -> string
199
    { args copystring
200
    } bind def
201
 
202
% Get a string argument that occupies the remainder of args.
203
   /sarg		% sarg -> string
204
    { args (") anchorsearch
205
       { pop /args exch def } { pop } ifelse
206
      args args length 1 sub get (") 0 get eq
207
       { args 0 args length 1 sub getinterval /args exch def } if
208
      args copystring
209
    } bind def
210
 
211
% Check that the keyword is the expected one.
212
   /checkline		% (EXPECTED-KEYWORD) checkline ->
213
    { dup keyword ne
214
       { (Expected ) print =
215
         (Line=) print keyword print ( ) print args print (\n) print stop
216
       } if
217
      pop
218
    } bind def
219
 
220
% Read a line and check its keyword.
221
   /getline		% (EXPECTED-KEYWORD) getline ->
222
    { nextline checkline
223
    } bind def
224
 
225
% Find the first/last non-zero bit of a non-zero byte.
226
   /fnzb
227
    { 0 { exch dup 128 ge { pop exit } { dup add exch 1 add } ifelse }
228
      loop
229
    } bind def
230
   /lnzb
231
    { 7 { exch dup 1 and 0 ne { pop exit } { -1 bitshift exch 1 sub } ifelse }
232
      loop
233
    } bind def
234
 
235
% ------ Type 1 encoding utilities ------ %
236
 
237
% Parse the side bearing and width information that begins a CharString.
238
% Arguments: charstring.  Result: sbx sby wx wy substring.
239
   /parsesbw
240
    { mark exch lenIV
241
       {		% stack: mark ... string dropcount
242
         dup 2 index length exch sub getinterval
243
	 dup 0 get dup 32 lt { pop exit } if
244
	 dup 246 le
245
	  { 139 sub exch 1 }
246
	  { dup 250 le
247
	     { 247 sub 8 bitshift 108 add 1 index 1 get add exch 2 }
248
	     { dup 254 le
249
		{ 251 sub 8 bitshift 108 add 1 index 1 get add neg exch 2 }
250
		{ pop dup 1 get 128 xor 128 sub
251
		  8 bitshift 1 index 2 get add
252
		  8 bitshift 1 index 3 get add
253
		  8 bitshift 1 index 4 get add exch 5
254
		} ifelse
255
	     } ifelse
256
	  } ifelse
257
       } loop
258
      counttomark 3 eq { 0 3 1 roll 0 exch } if
259
      6 -1 roll pop
260
    } bind def 
261
 
262
% Find the side bearing and width information that begins a CharString.
263
% Arguments: charstring.  Result: charstring sizethroughsbw.
264
   /findsbw
265
    { dup parsesbw 4 { exch pop } repeat skipsbw
266
    } bind def
267
   /skipsbw		% charstring sbwprefix -> sizethroughsbw
268
    { length 1 index length exch sub
269
      2 copy get 12 eq { 2 } { 1 } ifelse add
270
    } bind def
271
 
272
% Encode a number, and append it to a string.
273
% Arguments: str num.  Result: newstr.
274
   /concatnum
275
    { dup dup -107 ge exch 107 le and
276
       { 139 add 1 string dup 0 3 index put }
277
       { dup dup -1131 ge exch 1131 le and
278
          { dup 0 ge { 16#f694 } { neg 16#fa94 } ifelse add
279
	    2 string dup 0 3 index -8 bitshift put
280
	    dup 1 3 index 255 and put
281
	  }
282
	  { 5 string dup 0 255 put exch
283
	    2 copy 1 exch -24 bitshift 255 and put
284
	    2 copy 2 exch -16 bitshift 255 and put
285
	    2 copy 3 exch -8 bitshift 255 and put
286
	    2 copy 4 exch 255 and put
287
	    exch
288
	  }
289
	 ifelse
290
       }
291
      ifelse exch pop concatstrings
292
    } bind def
293
 
294
% ------ Point arithmetic utilities ------ %
295
 
296
   /ptadd { exch 4 -1 roll add 3 1 roll add } bind def
297
   /ptexch { 4 2 roll } bind def
298
   /ptneg { neg exch neg exch } bind def
299
   /ptpop { pop pop } bind def
300
   /ptsub { ptneg ptadd } bind def
301
 
302
% ------ The main program ------ %
303
 
304
   /readBDF		% <infilename> <outfilename> <fontname>
305
			%   <encodingname> <uniqueID> <xuid> readBDF -> <font>
306
    { /xuid exch def		% may be null
307
      /uniqueID exch def	% may be -1
308
      /encodingname exch def
309
	/encoding encodingname cvx exec def
310
      /fontname exch def
311
      /psname exch def
312
      /bdfname exch def
313
      gsave		% so we can set the CTM to the font matrix
314
 
315
%  Open the input files.  We don't open the output file until
316
%  we've done a minimal validity check on the input.
317
      bdfname (r) file /bdfile exch def
318
      /commentword ( ) def
319
 
320
%  Check for the STARTFONT.
321
      (STARTFONT) getline
322
      args (2.1) ne { (Not version 2.1\n) print stop } if
323
 
324
%  Initialize the font.
325
      /Font 20 dict def
326
      Font begin
327
      /FontName fontname def
328
      /PaintType 0 def
329
      /FontType 1 def
330
      uniqueID 0 gt { /UniqueID uniqueID def } if
331
      xuid null ne { /XUID xuid def } if
332
      /Encoding encoding def
333
      /FontInfo 20 dict def
334
      /Private 20 dict def
335
      currentdict end currentdict end
336
      exch begin begin		% insert font above environment
337
 
338
%  Initialize the Private dictionary in the font.
339
      Private begin
340
      /-! {string currentfile exch readhexstring pop} readonly def
341
      /-| {string currentfile exch readstring pop} readonly def
342
      /|- {readonly def} readonly def
343
      /| {readonly put} readonly def
344
      /BlueValues [] def
345
      /lenIV lenIV def
346
      /MinFeature {16 16} def
347
      /password 5839 def
348
      /UniqueID uniqueID def
349
      end		% Private
350
 
351
%  Invert the Encoding, for synthesizing composite characters.
352
      /decoding encoding length dict def
353
 
354
       { dup encoding exch get exch decoding 3 1 roll put }
355
      for
356
 
357
%  Now open the output file.
358
      psname (w) file /psfile exch def
359
 
360
%  Put out a header compatible with the Adobe "standard".
361
      (%!FontType1-1.0: ) ws fontname wt (000.000) wl
362
      (% This is a font description converted from ) ws
363
	bdfname wl
364
      (%   by bdftops running on ) ws
365
      statusdict /product get ws ( revision ) ws
366
      revision =string cvs ws (.) wl
367
 
368
%  Copy the initial comments, up to FONT.
369
      true
370
       { nextline
371
	 keyword (COMMENT) ne {exit} if
372
	  { (% Here are the initial comments from the BDF file:\n%) wl
373
	  } if false
374
	 (%) ws remarg wl
375
       } loop pop
376
      () wl
377
      /commentword (COMMENT) def	% do skip comments from now on
378
 
379
%  Read and process the FONT, SIZE, and FONTBOUNDINGBOX.
380
      % If we cared about FONT, we'd use it here.  If the BDF files
381
      % from MIT had PostScript names rather than X names, we would
382
      % care; but what's there is unusable, so we discard FONT.
383
      % The FONTBOUNDINGBOX may not be reliable, so we discard it too.
384
      (FONT) checkline
385
      (SIZE) getline
386
	/pointsize iarg def   /xres iarg def   /yres iarg def
387
      (FONTBOUNDINGBOX) getline
388
      nextline
389
 
390
%  Initialize the font bounding box bookeeping.
391
      /fbbxo 1000 def
392
      /fbbyo 1000 def
393
      /fbbxe -1000 def
394
      /fbbye -1000 def
395
 
396
%  Read and process the properties.  We only care about a few of them.
397
      keyword (STARTPROPERTIES) eq
398
       { iarg
399
          { nextline
400
	    properties keyword known
401
	     { FontInfo properties keyword get sarg readonly put
402
	     } if
403
	  } repeat
404
         (ENDPROPERTIES) getline
405
	 nextline
406
       } if
407
 
408
%  Compute and set the FontMatrix.
409
      Font /FontMatrix
410
       [ 0.001 0 0 0.001 xres mul yres div 0 0 ] readonly
411
      dup setmatrix put
412
 
413
%  Read and process the header for the bitmaps.
414
      (CHARS) checkline
415
	/ccount iarg def
416
 
417
%  Initialize the CharStrings dictionary.
418
      /charstrings ccount
419
	composites length add
420
	aliases length add
421
	accentedchars length add
422
	1 add dict def		% 1 add for .notdef
423
      /isfixedwidth true def
424
      /fixedwidth null def
425
      /subrcount 0 def
426
      /subrs [] def
427
 
428
%  Read the bitmap data.  This reads the remainder of the file.
429
%  We do this before processing the bitmaps so that we can compute
430
%  the correct FontBBox first.
431
      /chardata ccount dict def
432
      ccount -1 1
433
       { (STARTCHAR) getline
434
           /charname remarg def
435
	 (ENCODING) getline
436
	   /eindex iarg def
437
	   eindex dup 0 ge exch 255 le and
438
	    { charname /charname StandardEncoding eindex get def
439
	      charname /.notdef eq eindex 0 gt and
440
	       { /charname (A) eindex =string cvs concatstrings cvn def
441
	       }
442
	      if
443
	      (/) print charname =string cvs print (,) print print
444
	    }
445
	    { (/) print charname print
446
	    }
447
	   ifelse
448
	   10 mod 1 eq { (\n) print flush } if
449
	 (SWIDTH) getline
450
	   /swx iarg pointsize mul 1000 div xres mul 72 div def
451
	   /swy iarg pointsize mul 1000 div xres mul 72 div def
452
	 (DWIDTH) getline		% Ignore, use SWIDTH instead
453
	 (BBX) getline
454
	   /bbw iarg def  /bbh iarg def  /bbox iarg def  /bboy iarg def
455
	 nextline
456
	 keyword (ATTRIBUTES) eq
457
	  { nextline
458
	  } if
459
	 (BITMAP) checkline
460
 
461
% Update the font bounding box.
462
	 /fbbxo fbbxo bbox .min def
463
	 /fbbyo fbbyo bboy .min def
464
	 /fbbxe fbbxe bbox bbw add .max def
465
	 /fbbye fbbye bboy bbh add .max def
466
 
467
% Read the bits for this character.
468
	 /raster bbw 7 add 8 idiv def
469
	 /cbits raster bbh mul string def
470
	 cbits length 0 gt
471
	  { 0 raster cbits length raster sub
472
	      { cbits exch raster getinterval
473
	        bdfile buffer readline not
474
	         { (EOF in bitmap\n) print stop } if
475
		    % stack has <cbits.interval> <buffer.interval>
476
 
477
	        exch 2 copy readhexstring pop pop pop closefile
478
	      } for
479
	  } if
480
 
481
         (ENDCHAR) getline
482
 
483
% Save the character data.
484
	 chardata charname [swx swy bbw bbh bbox bboy cbits] put
485
       } for
486
 
487
      (ENDFONT) getline
488
 
489
% Allocate the buffers for the bitmap and the outline,
490
% according to the font bounding box.
491
      /fbbw fbbxe fbbxo sub def
492
      /fbbh fbbye fbbyo sub def
493
      /fraster fbbw 7 add 8 idiv def
494
      /bits fraster fbbh mul 200 .max 65535 .min string def
495
      /outline bits length 16 mul 65535 .min string def
496
 
497
%  Process the characters.
498
      chardata
499
       { exch /charname exch def  aload pop
500
	 /cbits exch def
501
	 /bboy exch def   /bbox exch def
502
	 /bbh exch def   /bbw exch def
503
	 /swy exch def   /swx exch def
504
 
505
% The bitmap handed to type1imagepath must have the correct height,
506
% because type1imagepath uses this to compute the scale factor,
507
% so we have to clear the unused parts of it.
508
	 /raster bbw 7 add 8 idiv def
509
	 bits dup 0 1 raster fbbh mul 1 sub
510
	  { 0 put dup } for
511
	 pop pop
512
	 bits raster fbbh bbh sub mul cbits putinterval
513
 
514
%  Compute the font entry, converting the bitmap to an outline.
515
	 bits 0 raster fbbh mul getinterval	% the bitmap image
516
	 bbw   fbbh				% bitmap width & height
517
	 swx   swy				% width x & y
518
	 bbox neg   bboy neg			% origin x & y
519
	 	% Account for lenIV when converting the outline.
520
	 outline  lenIV  outline length lenIV sub  getinterval
521
         type1imagepath
522
         length lenIV add
523
	 outline exch 0 exch getinterval
524
 
525
% Check for a fixed width font.
526
	 isfixedwidth
527
	  { fixedwidth null eq
528
	     { /fixedwidth swx def }
529
	     { fixedwidth swx ne { /isfixedwidth false def } if }
530
	    ifelse
531
	  } if
532
 
533
% Finish up the character.
534
	 copystring
535
	 charname exch charstrings 3 1 roll put
536
       } forall
537
 
538
%  Add CharStrings entries for aliases.
539
      aliases
540
       { charstrings 2 index known not charstrings 2 index known and
541
          { charstrings exch get charstrings 3 1 roll put
542
	  }
543
	  { pop pop
544
	  }
545
	 ifelse
546
       }
547
      forall
548
 
549
%  If this is not a fixed-width font, synthesize missing characters
550
%  out of available ones.
551
      isfixedwidth not
552
       { false composites
553
	  { 1 index charstrings exch known not
554
	    1 index { decoding exch known and } forall
555
	     { ( /) print 1 index bits cvs print
556
	       /combine exch def
557
 
558
		{ dup combine exch get decoding exch get
559
		  bits 3 1 roll put
560
		} for
561
	       bits 0 combine length getinterval copystring
562
	       [ exch /compose_proc load aload pop ] cvx
563
	       charstrings 3 1 roll put
564
	       pop true
565
	     }
566
	     { pop pop }
567
	    ifelse
568
	  }
569
	 forall flush
570
	  { Private /composematrix matrix put
571
	    Private /compose /compose load put
572
	  }
573
	 if
574
       }
575
      if
576
 
577
%  Synthesize accented characters with seac if needed and possible.
578
      accentedchars
579
       { aload pop /accent exch def /base exch def
580
         buffer cvs /accented exch def
581
	 charstrings accented known not
582
	 charstrings base known and
583
	 charstrings accent known and
584
	 StandardDecoding base known and
585
	 StandardDecoding accent known and
586
	 encoding StandardDecoding base get get base eq and
587
	 encoding StandardDecoding accent get get accent eq and
588
	  { ( /) print accented print
589
	    charstrings base get findsbw 0 exch getinterval
590
	    /acstring exch def		% start with sbw of base
591
	    charstrings accent get parsesbw
592
	    4 { pop } repeat		% just leave sbx
593
	    acstring exch concatnum
594
 
595
	    decoding base get concatnum		% bchar
596
	    decoding accent get concatnum	% achar
597
	    s_seac concatstrings
598
	    charstrings exch accented copystring exch put
599
	  } if
600
       } forall
601
 
602
%  Make a CharStrings entry for .notdef.
603
      outline lenIV <8b8b0d0e> putinterval	% 0 0 hsbw endchar
604
      charstrings /.notdef outline 0 lenIV 4 add getinterval copystring put
605
 
606
%  Encrypt the CharStrings and Subrs (in place).
607
      charstrings
608
       {	% Be careful not to encrypt aliased characters twice,
609
		% since they share their CharString.
610
	 aliases 2 index known
611
	  { charstrings aliases 3 index get .knownget
612
	     { 1 index ne }
613
	     { true }
614
	    ifelse
615
	  }
616
	  { true
617
	  }
618
	 ifelse
619
	 1 index type /stringtype eq and
620
          { 4330 exch dup .type1encrypt exch pop
621
	    readonly charstrings 3 1 roll put
622
	  }
623
	  { pop pop
624
	  }
625
	 ifelse
626
       }
627
      forall
628
 
629
       { dup subrs exch get
630
	 4330 exch dup .type1encrypt exch pop
631
	 subrs 3 1 roll put
632
       }
633
      for
634
 
635
%  Make most of the remaining entries in the font dictionaries.
636
 
637
% The Type 1 font machinery really only works with a 1000 unit
638
% character coordinate system.  Set this up here, by computing the factor
639
% to make the X entry in the FontMatrix come out at exactly 0.001.
640
      /fontscale 1000 fbbh div yres mul xres div def
641
      Font /FontBBox
642
       [ fbbxo fontscale mul
643
	 fbbyo fontscale mul
644
	 fbbxe fontscale mul
645
	 fbbye fontscale mul
646
       ] cvx readonly put
647
      Font /CharStrings charstrings readonly put
648
      FontInfo /FullName known not
649
       { % Some programs insist on FullName being present.
650
         FontInfo /FullName FontName dup length string cvs put
651
       }
652
      if
653
      FontInfo /isFixedPitch isfixedwidth put
654
      subrcount 0 gt
655
       { Private /Subrs subrs 0 subrcount getinterval readonly put
656
       } if
657
 
658
%  Determine the italic angle and underline position
659
%  by actually installing the font.
660
      save
661
      /_temp_ Font definefont setfont
662
      [1000 0 0 1000 0 0] setmatrix		% mitigate rounding problems
663
% The italic angle is the multiple of -5 degrees
664
% that minimizes the width of the 'I'.
665
 
666
       { dup rotate
667
         newpath 0 0 moveto (I) false charpath
668
	 dup neg rotate
669
         pathbbox pop exch pop exch sub
670
	 dup 3 index lt { 4 -2 roll } if
671
	 pop pop
672
       }
673
      for pop
674
% The underline position is halfway between the bottom of the 'A'
675
% and the bottom of the FontBBox.
676
      newpath 0 0 moveto (A) false charpath
677
      FontMatrix concat
678
      pathbbox pop pop exch pop
679
%  Put the values in FontInfo.
680
      3 -1 roll
681
      restore
682
      Font /FontBBox get 1 get add 2 div cvi
683
      dup FontInfo /UnderlinePosition 3 -1 roll put
684
      2 div abs FontInfo /UnderlineThickness 3 -1 roll put
685
      FontInfo /ItalicAngle 3 -1 roll put
686
 
687
%  Clean up and finish.
688
      grestore
689
      bdfile closefile
690
      Font currentdict end end begin		% remove font from dict stack
691
      (\n) print flush
692
 
693
    } bind def
694
 
695
% ------ Reader for AFM files ------ %
696
 
697
% Dictionary for looking up character keywords
698
   /cmdict 6 dict dup begin
699
      /C { /c iarg def } def
700
      /N { /n warg copystring def } def
701
      /WX { /w narg def } def
702
      /W0X /WX load def
703
      /W /WX load def
704
      /W0 /WX load def
705
   end def
706
 
707
   /readAFM		% fontdict afmfilename readAFM -> fontdict
708
    { (r) file /bdfile exch def
709
      /Font exch def
710
      /commentword (Comment) def
711
 
712
%  Check for the StartFontMetrics.
713
      (StartFontMetrics) getline
714
      args cvr 2.0 lt { (Not version 2.0 or greater\n) print stop } if
715
 
716
%  Look for StartCharMetrics, then parse the character metrics.
717
%  The only information we care about is the X width.
718
      /metrics 0 dict def
719
       { nextline
720
         keyword (EndFontMetrics) eq { exit } if
721
	 keyword (StartCharMetrics) eq
722
	  { iarg dup dict /metrics exch def
723
	     { /c -1 def /n null def /w null def
724
	       nextline buffer
725
		{ token not { exit } if
726
		  dup cmdict exch known
727
		   { exch /args exch def   cmdict exch get exec   args }
728
		   { pop }
729
		  ifelse
730
		} loop
731
	       c 0 ge n null ne or w null ne and
732
		{ n null eq { /n Font /Encoding get c get def } if
733
		  metrics n w put
734
		}
735
	       if
736
	     }
737
	    repeat
738
	    (EndCharMetrics) getline
739
	  } if
740
       } loop
741
 
742
%  Insert the metrics in the font.
743
       metrics length 0 ne
744
	{ Font /Metrics metrics readonly put
745
	} if
746
      Font
747
    } bind def
748
 
749
end		% envBDF
750
 
751
% Enter the main program in the current dictionary.
752
/bdfafmtops		% infilename afmfilename* outfilename fontname
753
			%   encodingname uniqueID xuid
754
 { envBDF begin
755
     7 -2 roll exch 7 2 roll	% afm* in out fontname encodingname uniqueID xuid
756
     readBDF		% afm* font
757
     exch { readAFM } forall
758
     save exch
759
     dup /FontName get exch definefont
760
     setfont
761
     psfile writefont
762
     restore
763
     psfile closefile
764
   end
765
 } bind def
766
 
767
% If the program was invoked from the command line, run it now.
768
[ shellarguments
769
 { counttomark 4 ge
770
    { dup 0 get
771
      dup 48 ge exch 57 le and		% last arg starts with a digit?
772
       { /StandardEncoding }		% no encodingname
773
       { cvn }				% have encodingname
774
      ifelse
775
      exch (.) search			% next-to-last arg has . in it?
776
       { mark 4 1 roll			% have xuid
777
          { cvi exch pop exch (.) search not { exit } if }
778
	 loop cvi ]
779
	 3 -1 roll cvi exch
780
       }
781
       { cvi null			% no xuid
782
       }
783
      ifelse
784
      counttomark 5 roll
785
      counttomark 6 sub array astore
786
      7 -2 roll cvn 7 -3 roll		% make sure fontname is a name
787
      bdfafmtops
788
    }
789
    { cleartomark
790
      (Usage:\n  bdftops xx.bdf [yy1.afm ...] zz.gsf fontname uniqueID [xuid] [encodingname]\n) print flush
791
      mark
792
    }
793
   ifelse
794
 }
795
if pop