1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
|
% Copyright (C) 1994, 1996, 1997, 1998, 1999 Aladdin Enterprises. All rights reserved.
%
% This file is part of Aladdin Ghostscript.
%
% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
% or distributor accepts any responsibility for the consequences of using it,
% or for whether it serves any particular purpose or works at all, unless he
% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
% License (the "License") for full details.
%
% Every copy of Aladdin Ghostscript must include a copy of the License,
% normally in a plain ASCII text file named PUBLIC. The License grants you
% the right to copy, modify and redistribute Aladdin Ghostscript, but only
% under certain conditions described in the License. Among other things, the
% License requires that the copyright notice and this notice be preserved on
% all copies.
% pdf_font.ps
% PDF font operations.
/.setlanguagelevel where { pop 2 .setlanguagelevel } if
.currentglobal true .setglobal
/pdfdict where { pop } { /pdfdict 100 dict def } ifelse
GS_PDF_ProcSet begin
pdfdict begin
% We cache the PostScript font in an additional element of the
% font resource dictionary, called PSFont.
% ---------------- Encodings ---------------- %
% Apply a list of differences to an Encoding.
% Note that the differences may cause the array to grow.
/updateencoding { % <encoding> <differences> updateencoding <enc'>
% Calculate the length of the result.
exch 0 2 index {
dup type /nametype ne { exch pop } { pop 1 add } ifelse
} forall
1 index length .max array dup 0 4 -1 roll putinterval
exch 0 exch {
% Stack: enc' code element
dup type /nametype ne
{ exch pop }
{ 3 copy put pop 1 add }
ifelse
} forall pop
} bdef
% Get the Encoding for a font.
/getencoding % <base-encoding> <font-resource> getencoding <enc>
{ /Encoding knownoget
{ dup type /nametype eq
{ exch pop findencoding
}
{ dup /BaseEncoding knownoget
{ findencoding 3 -1 roll pop exch
}
if
/Differences knownoget { updateencoding } if
}
ifelse
}
if
} bdef
% Rename a font with a generated name.
/renamefont { % <fontdict> renamefont <font'>
dup /FontName 2 copy get genfontname dup 5 1 roll put definefont
} bind def
% Adjust a font according to the Encoding and Widths in the font resource.
/adjustfont { % <font-resource> <font> adjustfont <font'>
getfontencoding getfontmetrics 4 -1 roll pop .updatefont { renamefont } if
} bind def
% Get the (possibly modified) encoding of a font.
/getfontencoding % <font-resource> <font> getfontencoding
% <font-resource> <font> <encoding>
{ dup /Encoding .knownget { 2 index getencoding } { null } ifelse
} bdef
% Get the metrics of a font, if specified.
/getfontmetrics % <font-resource> <font> <encoding> getfontmetrics
% <font-resource> <font> <encoding> <Metrics|null>
{ 2 index /Widths known
{ 2 dict begin
/Encoding exch def
/Metrics Encoding length dict def
exch
% Stack: font font-res
% Note that widths are always based on a 1000-unit
% character space, but the FontMatrix may specify
% some other scale factor. Compensate for this here,
% by scaling the Widths if necessary.
0.001 2 index /FontMatrix get 0 get div
% Stack: font font-res mscale
1 index /FirstChar oget dup 1 4 index /LastChar oget
{ % Stack: font font-res mscale first-char index
Encoding 1 index get
4 index /Widths oget 2 index 4 index sub get
% Stack: font font-res mscale first-char index charname width
4 index mul
% There is a hack here to deal with encodings where the
% same character appears more than once, because the Metrics
% dictionary works by character name, not by character code.
% Because of this, we can't deal with Width vectors that
% specify different widths for the same character name
% appearing multiple times in the Encoding.
Metrics 2 index .knownget not { 0 } if 0 ne {
pop pop
} {
% Work around a bug in pdfTeX, which can generate Encoding
% vectors containing nulls.
1 index null ne {
Metrics 3 1 roll put
} {
pop pop
} ifelse
}
ifelse pop
}
for pop
% Now fill in the MissingWidth for any encoded characters
% that aren't in Metrics already.
% Stack: font font-res mscale
Metrics 2 index /FontDescriptor oget
/MissingWidth knownoget { 2 index mul } { 0 } ifelse exch
Encoding
{ % Stack: font font-res mscale missing-width metrics charname
% Work around the abovementioned pdfTeX bug.
dup null ne {
2 copy known not { 2 copy 4 index put } if pop
} {
pop
} ifelse
}
forall pop pop pop
exch Encoding Metrics end
}
{ null
}
ifelse
} bdef
% ---------------- Descriptors ---------------- %
% Partial descriptors for the 14 built-in fonts. Note that
% from PDF 1.1 to PDF 1.2, the meaning of the Flag 6 in the FontDescriptor
% object has undergone a subtle change in its meaning which has serious
% consequences for searching with Acrobat:
% In PDF 1.1, the flag meant: Font has StandardEncoding
% In PDF 1.2, the flag means: Font has (subset of) StandardRomanCharacterSet
/standardfontdescriptors mark
/Courier mark /Flags 16#23 .dicttomark
/Courier-Oblique 1 index
/Courier-Bold 1 index
/Courier-BoldOblique 1 index
/Helvetica mark /Flags 16#20 .dicttomark
/Helvetica-Oblique 1 index
/Helvetica-Bold 1 index
/Helvetica-BoldOblique 1 index
/Times-Roman mark /Flags 16#22 .dicttomark
/Times-Bold 1 index
/Times-Italic mark /Flags 16#62 .dicttomark
/Times-BoldItalic 1 index
/Symbol mark /Flags 16#4 .dicttomark
/ZapfDingbats 1 index
.dicttomark readonly def
% ---------------- Utilities ---------------- %
% Fabricate a font name by adding ?'s on the end.
/genfontname % <name> genfontname <name>
{ dup length string cvs
{ (?) concatstrings
dup cvn FontDirectory exch known not { cvn exit } if
}
loop
} bdef
% Find a font, and adjust its encoding if necessary.
/pdffindfont { % <font-resource> <fontname> pdffindfont <font>
% If the font isn't available, synthesize one based on
% its descriptor.
dup /Font resourcestatus {
pop pop findfont
} {
1 index /FontDescriptor knownoget {
% Stack: font-res fontname fontdesc
dup /Flags oget
dup 16#40 and -6 bitshift % 1, oblique/italic
1 index 16#40000 and -17 bitshift add % 2, bold
exch 16#2 and 2 bitshift add % 8, serif
% We should look at the fixed flag, too.
% Stack: font-res fontname fontdesc properties
1 index /FontName oget exch
1 index .fontnameproperties or
.substitutefontname
% Stack: font-res fontname fontdesc substname|null
Fontmap 1 index known not {
% No available good substitution, use the standard one.
pop 1 index .substitutefont
} if
QUIET not {
(Substituting font ) print dup =only
( for ) print 2 index =only (.\n) print flush
} if
3 -1 roll pop findfont
% Stack: font-res fontdesc font
% If this is a small-caps font, replace the CharString
% entries for a..z.
exch /Flags oget 16#20000 and 0 ne {
true .copyfontdict
dup /CharStrings 2 copy get dup length dict .copydict
4 index /FirstChar get 97 .max
5 index /LastChar get 122 .min 1 exch {
% Stack: font-res font' font' /CharStrings charstrings code
% Note that this only remaps a-z, not accented characters.
5 index /Widths oget 1 index 7 index /FirstChar get sub oget
1 string dup 0 5 -1 roll put
% Stack: font-res font' font' /CharStrings charstrings code
% width (x)
2 index exch dup cvn exch
dup 0 2 copy get 32 sub put 4 -1 roll {
% Stack: operand (X) width
0 setcharwidth exch pop
% ****** I HAVE ABSOLUTELY NO IDEA WHY THE NUMBER
% ****** 70 PRODUCES THE CORRECT OUTPUT HERE.
70 70 scale 0 0 moveto show
} /exec cvx 4 packedarray cvx put
} for put
renamefont
} if
} {
% No descriptor available, use the default algorithm.
findfont
} ifelse
} ifelse adjustfont
} bdef
% ---------------- Type 1 fonts ---------------- %
/buildType1 % <Type1-font-resource> buildType1 <font>
{ dup /BaseFont get pdffindfont
} bdef
% The state dictionary for the embedded Type 1 font reading procedure
% has the following keys and values:
% data - stream (filter)
% buffer, buffer2 - string
% leftstr - string containing (non-negative) integer
% sectionstr - string containing a character 0 .. 2
% stream - (stream) dictionary
% proc - procedure of the form {-dict- type1read}
% When the procedure is executing, this dictionary is current.
% leftstr and sectionstr are strings so that we can change their values
% reliably in case the font executes a restore!
% Read an embedded Type 1 font.
/readfontfilter % <proc> readfontfilter <filter>
{ % We make this a separate procedure so that we can
% redefine it when we're writing PostScript.
0 () /SubFileDecode filter
} bdef
/readtype1dict 5 dict dup begin
/definefont {
dup wcheck not { dup length dict copy } if
exch pop savedFontName exch
//systemdict /definefont get exec
} bdef
/eexec {
55665 /eexecDecode filter
//systemdict begin readtype1dictcopy begin cvx stopped
currentdict readtype1dictcopy eq { end } if
currentdict //systemdict eq { end } if
{ stop } if
} bdef
end readonly def
/readtype1 % <font-resource> <stream-dict> readtype1 <font>
{ % Read the definition, using a procedure-based filter
% that turns binary/hex conversion on and off
% at the right times.
PDFfile fileposition 3 1 roll
7 dict begin
/leftstr ( ) 10 string copy def
dup /Length1 oget leftstr cvs pop
/sectionstr <00> 1 string copy def
/stream 1 index def
true resolvestream /data exch def
/buffer 1000 string def % arbitrary
/buffer2 buffer length 2.1 div cvi 1 sub string def
currentdict end
/type1read cvx 2 array astore cvx dup 0 get /proc 2 index put
readfontfilter
% Some buggy embedded fonts leave extra junk on the stack,
% so we have to make a closure that records the stack depth
% in a fail-safe way.
//systemdict begin
% Rebind definefont so we can substitute the FontName
% from the descriptor.
//readtype1dict dup length 2 add dict copy begin
1 index /FontDescriptor oget /FontName oget /savedFontName exch def
/readtype1dictcopy currentdict def
{ run } aload pop count 1 sub 2 packedarray cvx exec
end end
count exch sub { pop } repeat
PDFfile 3 -1 roll setfileposition
/FontDescriptor oget /FontName oget findfont
} bdef
% Execute the appropriate reading procedure.
/type1read % <dict> type1read <string>
{ begin leftstr cvi
{ type1read1 type1read2 type1read3 } sectionstr 0 get get exec
( ) leftstr copy cvs pop end
} bdef
% Read the next block of data into the buffer.
/type1readdata % <left> <buffer> type1readdata <substring> <left'>
{ 0 2 index 2 index length min getinterval
% Adobe requires readstring to signal an error if given
% an empty string. Work around this nonsense here.
dup length 0 ne { data exch readstring pop } if
dup length 3 -1 roll exch sub
DEBUG
{ dup =only ( read ) print
1 index length =only (: ) print
1 index == flush
} if
} bdef
% Read the next block of the initial text portion.
/type1read1 % <left> type1read1 <string> <left'>
{ DEBUG { (read1 ) print } if
dup 0 eq
{ pop sectionstr 0 1 put
stream /Length2 oget type1read2
}
{ buffer type1readdata
}
ifelse
} bdef
% Read the next block of the encrypted portion.
/type1trailer
(0000000000000000000000000000000000000000000000000000000000000000\n\
0000000000000000000000000000000000000000000000000000000000000000\n\
0000000000000000000000000000000000000000000000000000000000000000\n\
0000000000000000000000000000000000000000000000000000000000000000\n\
0000000000000000000000000000000000000000000000000000000000000000\n\
0000000000000000000000000000000000000000000000000000000000000000\n\
0000000000000000000000000000000000000000000000000000000000000000\n\
0000000000000000000000000000000000000000000000000000000000000000\n\
cleartomark\n)
readonly def
/type1read2 % <left> type1read2 <string> <left'>
{ DEBUG { (read2 ) print } if
dup 0 eq
{ pop sectionstr 0 2 put
stream /Length3 oget
dup 0 eq
{ DEBUG { (trailer ) print } if
type1trailer exch
}
{ type1read3
}
ifelse
}
{ buffer2 type1readdata exch
buffer /ASCIIHexEncode filter dup 3 -1 roll writestring closefile
buffer (>) search pop exch pop exch pop exch
}
ifelse
} bdef
% Read the next block of the final text portion.
% When finished, this procedure returns an empty string.
/type1read3 % <left> type1read3 <string> <left'>
{ DEBUG { (read3 ) print } if
buffer type1readdata
} bdef
% ---------------- Type 3 fonts ---------------- %
/.notdefEncoding 256 { /.notdef } repeat 256 packedarray def
/buildType3 % <Type3-font-resource> buildType3 <font>
{ 8 dict begin
/FontType 3 def
/Resources 1 index /Resources knownoget { oforce } { 0 dict } ifelse def
/FontBBox 1 index /FontBBox get cvx def
/FontMatrix 1 index /FontMatrix oget def
/CharProcs 1 index /CharProcs oget def
/FontName 1 index /Name get genfontname def
/Encoding .notdefEncoding 2 index getencoding def
/BuildGlyph {
% Stack: font glyphname
1 index /CharProcs get exch oget
PDFfile fileposition exch
false resolvestream
% Stack: font filepos stream
% Don't let setgcolor set the color inside the BuildGlyph
% procedure, because this causes an /undefined error.
q null /FillColor gput null /StrokeColor gput
2 index /Resources get exch pdfopdict .pdfruncontext
Q
PDFfile exch setfileposition pop
} bdef
FontName currentdict end definefont exch pop
} bdef
% ---------------- TrueType fonts ---------------- %
/TTfonts mark
/Arial /Helvetica
/Arial,Italic /Helvetica-Oblique
/Arial,Bold /Helvetica-Bold
/Arial,BoldItalic /Helvetica-BoldOblique
/CourierNew /Courier
/CourierNew,Bold /Courier-Bold
/TimesNewRoman /Times-Roman
/TimesNewRoman,Italic /Times-Italic
/TimesNewRoman,Bold /Times-Bold
/TimesNewRoman,BoldItalic /Times-BoldItalic
.dicttomark readonly def
/buildTrueType % <TrueType-font-resource> buildTrueType <font>
{ dup /BaseFont get
dup TTfonts exch .knownget { exch pop } if pdffindfont
} bdef
% Read an embedded TrueType font.
/readtruetype { % <font-resource> <stream-dict> readtruetype <font>
% This is much simpler than readtype1, because we don't
% have to deal with the tripartite .PFB format.
PDFfile fileposition 3 1 roll
true resolvestream readfontfilter
% Stack: filepos fontres stream
1 index /Subtype get /CIDFontType2 eq {
.loadttcidfont
} {
.loadttfont
} ifelse
exch pop
PDFfile 3 -1 roll setfileposition
} bdef
% ---------------- Type 0 fonts ---------------- %
% Predefine the known CMaps, but only create them on demand.
/knownCMaps mark
/Identity-H { /Identity-H 0 makeIdentityCMap }
/Identity-V { /Identity-V 1 makeIdentityCMap }
.dicttomark def
/makeIdentityCMap { % <cmapname> <wmode> .makeIdentityCMap -
.currentglobal true .setglobal 3 1 roll
/CIDInit /ProcSet findresource begin
12 dict begin
/WMode exch def
/CMapName exch def
begincmap
/CIDSystemInfo 3 dict dup begin
/Registry (Adobe) def
/Ordering (Japan1) def
/Supplement 0 def
end def
%/CMapName ... def
/CMapVersion 1 def
/CMapType 1 def
%/WMode ... def
2 begincodespacerange
<0001> <00ff>
<0100> <ffff>
endcodespacerange
2 begincidrange
<0001> <00ff> 1
<0100> <ffff> 256
endcidrange
endcmap
CMapName currentdict /CMap defineresource
knownCMaps CMapName 2 index put
end % CMap
end % CIDInit ProcSet
exch .setglobal
} bdef
/buildType0 % <Type0-font-resource> buildType0 <font>
{ 10 dict begin
/FontType 0 def
/FontMatrix 1 index /FontMatrix knownoget not { matrix } if def
/FontName 1 index /BaseFont get def
/FMapType 9 def
/Encoding [
0 1 4 index /DescendantFonts oget length 1 sub { } for
] def
/FDepVector [
2 index /DescendantFonts oget { exec resourcefont } forall
] def
/CMap 1 index /Encoding oget
dup type /nametype eq {
dup /CMap resourcestatus {
pop pop /CMap findresource
} {
knownCMaps 1 index .knownget
{ exch pop exec } { /undefined signalerror } ifelse
} ifelse
} {
resolvestream
} ifelse
def
FontName currentdict end definefont exch pop
} bdef
% ---------------- CIDFontType0/2 fonts ---------------- %
% Insert metrics into a CIDFont, by saving the PDF W, W2, DW, and DW2
% arrays and using a (currently very inefficient) CDevProc.
/addCIDmetrics { % <CIDFont-resource> addCIDmetrics <fontdict>
dup /BaseFont get /CIDFont findresource
dup length 5 add dict .copydict
dup /FID undef
dup /UniqueID undef
dup /XUID undef
% Insert the widths into the font.
{W W2 DW DW2} {
% Stack: pdfresource newfont key
2 index 1 index .knownget {
2 index 3 1 roll put
} {
pop
} ifelse
} forall
dup /CDevProc 1 index /CIDWProc load /exec load 3 packedarray cvx put
exch pop
} bdef
% Apply the [D]W[2] metrics to a character before displaying.
/CIDWProc { % <w0x> <w0y> <llx> <lly> <urx> <ury>
% <w1x> <w1y> <vx> <vy> <cid> <font> CIDWproc
% <w0x'> ... <vy'>
begin
% Look up and apply [D]W
10 index
currentdict /DW .knownget { 1000 div exch pop } if
currentdict /W .knownget {
% Search the W array for the CID.
% ****** NOT IMPLEMENTED YET ******
pop
} if
0 13 2 roll 11 -2 roll pop pop
% Look up and apply [D]W2
% ****** NOT IMPLEMENTED YET ******
pop end
} bdef
/buildCIDType0 { % <CIDFontType0-font-resource> buildCIDType0 <font>
addCIDmetrics dup /CIDFontName get exch /CIDFont defineresource
} bdef
/buildCIDType2 { % <CIDFontType2-font-resource> buildCIDType2 <font>
addCIDmetrics
%****** Handle CIDToGIDMap ******
dup /BaseFont get exch /CIDFont defineresource
} bdef
% ---------------- Other embedded fonts ---------------- %
/fontloadprocs mark
/Type1C /readType1C cvx
.dicttomark readonly def
% Read an embedded compressed font.
/readType1C % <font-resource> <stream-dict> readType1C <font>
{ PDFfile fileposition 3 1 roll
dup true resolvestream dup readfontfilter
% Stack: pos resource streamdict stream filter
3 index /FontDescriptor oget /FontName oget
1 index FRD
closefile closefile pop
PDFfile 3 -1 roll setfileposition
/FontDescriptor oget /FontName oget findfont
} bdef
% ---------------- Font lookup ---------------- %
/fonttypeprocs mark % <font-resource> -proc- <font>
/Type0 /buildType0 cvx
/Type1 /buildType1 cvx
/MMType1 1 index
/Type3 /buildType3 cvx
/TrueType /buildTrueType cvx
/CIDFontType0 /buildCIDType0 cvx
/CIDFontType2 /buildCIDType2 cvx
.dicttomark readonly def
/resourcefont % <font-resource> resourcefont <font>
{ dup /PSFont .knownget
{ /FID .knownget { type /fonttype eq } { false } ifelse }
{ false }
ifelse
{ /PSFont get
}
{ dup dup /FontDescriptor knownoget
{ % Stack: font-res font-res font-desc
dup /FontFile knownoget
{ exch pop 1 index 3 1 roll readtype1 adjustfont true }
{ dup /FontFile2 knownoget
{ exch pop 1 index 3 1 roll readtruetype adjustfont true }
{ /FontFile3 knownoget
{ 1 index exch dup /Subtype get fontloadprocs exch get exec adjustfont true }
{ false }
ifelse
}
ifelse
}
ifelse
}
{ false }
ifelse
% Stack: font-res font-res false
% -or-: font-res font true
not
{ dup /Subtype get fonttypeprocs exch get exec }
if
2 copy /PSFont exch put
exch pop
}
ifelse
} bdef
drawopdict begin
/d0 /setcharwidth load def
/d1 /setcachedevice load def
/Tf
{ 1 index Page /Font rget not { 1 index /invalidfont signalerror } if
resourcefont exch Tf pop
} bdef
end
end % pdfdict
end % GS_PDF_ProcSet
.setglobal
|