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
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
|
% Copyright (C) 1994, 2000 Aladdin Enterprises. All rights reserved.
%
% This software is provided AS-IS with no warranty, either express or
% implied.
%
% This software is distributed under license and may not be copied,
% modified or distributed except as expressly authorized under the terms
% of the license contained in the file LICENSE in this distribution.
%
% For more information about licensing, please refer to
% http://www.ghostscript.com/licensing/. For information on
% commercial licensing, go to http://www.artifex.com/licensing/ or
% contact Artifex Software, Inc., 101 Lucas Valley Road #110,
% San Rafael, CA 94903, U.S.A., +1(415)492-9861.
% $Id$
% Definitions for most of the PDF operators.
.currentglobal //true .setglobal
% Define pdfmark. Don't allow it to be bound in.
% Also don't define it in systemdict, because this leads some Adobe code
% to think this interpreter is a distiller.
% (If this interpreter really is a distiller, don't do this.)
systemdict /pdfmark known not
{ userdict /pdfmark { cleartomark } bind put } if
userdict /GS_PDF_ProcSet 127 dict dup begin
% ---------------- Abbreviations ---------------- %
/bdef { bind def } bind def
% ---------------- Graphics state stack ---------------- %
% PDF adds a number of parameters to the graphics state.
% We implement this by pushing and popping a dictionary
% each time we do a PDF gsave or grestore.
% The keys in this dictionary are as follows:
% self % identifies the dictionary as one of ours
% ClipRect % (optional)
% Show
% TextSaveMatrix % matrix at time of BT (iff within BT/ET)
% (The following correspond directly to PDF state parameters.)
% AlphaIsShape
% FillConstantAlpha
% FillColor
% FillColorSpace
% FillOverprint
% SoftMask
% StrokeConstantAlpha
% StrokeColor
% StrokeColorSpace
% StrokeOverprint
% TextSpacing
% TextHScaling
% Leading
% TextFont
% TextLineMatrix
% TextMatrix
% TextRise
% TextRenderingMode
% WordSpacing
% (The following is cached information derived from other graphics state params)
% FontMatrixNonHV % TextFont.FontMatrix alters horz/vert glyph advance vector direction
/nodict 1 dict def
nodict /self { //nodict } executeonly put % to avoid recursion in dumps
nodict readonly pop
/dictbeginpage { % <initialdict> dictbeginpage -
20 dict copy dup begin
1 packedarray cvx executeonly /self exch def
graphicsbeginpage textbeginpage
} bdef
/endpage { % - endpage -
showpage end
} bdef
/graphicsbeginpage {
initgraphics
//true .setaccuratecurves
currentdict /ClipRect knownoget { aload pop rectclip } if
0 g 0 G //false op //false OP 0 OPM
1 ca 1 CA //null SMask //false AIS /Compatible BM //true TK
} bdef
/gput % <value> <key> gput -
{
currentdict /n known {
pop pop
( **** Ignoring changes to the graphic state after operator 'W'.\n)
pdfformaterror
} {
exch currentdict //nodict eq { /self dup load end 5 dict begin def } if
def
} ifelse
} bdef
/q {
gsave //nodict begin
PDFusingtransparency { .pushextendedgstate } if
} bdef
% Some PDF files have excess Q operators!
/Q {
//false
{ currentdict /n known { end pop //true } { exit } ifelse
} loop {
( **** Dropping unfinished 'W' mode at 'Q'.\n)
pdfformaterror
} if
currentdict /self .knownget {
exec //nodict eq {
end
PDFusingtransparency { .popextendedgstate } if
% Restore graphics state, but do not modify path. Paths are not part
% of the PDF graphics state; see 4.4.1 of PDF reference 3rd ed.
% Collecting the path with one ctm and re-playing it with another ctm
% transforms the path exactly as PDF needs.
.getpath grestore newpath { exec } forall
//false
} {
//true
} ifelse
} {
//true % formaterror -- not a gsave dict
} ifelse
{ (\n **** File has unbalanced q/Q operators \(too many Q's\) ****\n)
pdfformaterror
} if
} bdef
% Save PDF gstate
/qstate { % - qstate <qstate>
gstate
} bdef
% Set PDF gstate
/setqstate { % <qstate> setqstate -
{ matrix setmatrix //false upath } stopped {
pop setgstate newpath
} {
% Save the CTM, set identity during the uappend, then set the CTM
exch setgstate matrix currentmatrix matrix setmatrix
exch newpath uappend setmatrix
} ifelse
} bdef
% Save most of graphic state attributes.
% - get-gs-attrs ...
/get-gs-attrs {
currentsmoothness
currentflat
currentoverprint
currentstrokeadjust
currentdash
currentmiterlimit
currentlinejoin
currentlinecap
currentlinewidth
currentfont
currentcolor
currentcolorspace
{ currentpoint } stopped
matrix currentmatrix
} bdef
% Restore most of graphic state attributes.
% ... get-gs-attrs -
/set-gs-attrs {
setmatrix
{ newpath } { moveto } ifelse
setcolorspace
setcolor
setfont
setlinewidth
setlinecap
setlinejoin
setmiterlimit
setdash
setstrokeadjust
setoverprint
setflat
setsmoothness
} bdef
% ---------------- Color setting ---------------- %
/fcput % <color> <colorspace> fcput -
{ /FillColorSpace gput /FillColor gput
} bdef
/scput % <color> <colorspace> scput -
{ /StrokeColorSpace gput /StrokeColor gput
} bdef
/csput % <colorspace> csput -
{ csset 2 copy fcput scput
} bdef
/csdevgray [/DeviceGray] readonly def
/csdevrgb [/DeviceRGB] readonly def
/csdevcmyk [/DeviceCMYK] readonly def
/cspattern [/Pattern] readonly def
/nullpatternproc { pop } bdef
/nullpattern mark
/PatternType 1 /PaintType 1 /TilingType 3 /BBox [0 0 1 1]
/XStep 1 /YStep 1 /PaintProc //nullpatternproc
.dicttomark readonly def
% Each entry in the color space dictionary is a procedure of the form
% <cspace> -proc- <cspace> <initial-color>
/CSdict mark
/DeviceGray { pop //csdevgray 0 } bind
/DeviceRGB { pop //csdevrgb [0 0 0] cvx } bind
/DeviceCMYK { pop //csdevcmyk [0 0 0 1] cvx } bind
/CIEBasedA { 0 } bind
/CIEBasedABC { [0 0 0] cvx } bind
/CalGray { pop //csdevgray 0 } bind
/CalRGB { pop //csdevrgb [0 0 0] cvx } bind
/Lab {[0 0 0] cvx } bind
/ICCBased { [ 1 index 1 oget /N get { 0 } repeat ] cvx } bind
/Separation { 1 } bind
/DeviceN { % What is the correct value??
[ 1 index 1 get length { 1 } repeat ] cvx
} bind
/Indexed { 0 } bind
/Pattern {
dup type /nametype eq 1 index length 1 eq or {
pop //cspattern //nullpattern matrix makepattern
} {
//nullpattern matrix makepattern 1 index 1 get csset
% Stack: patternspace nullpattern basecolor basespace
pop [ 3 1 roll dup type /arraytype eq { aload pop } if
counttomark -1 roll ] cvx
} ifelse
} bind
.dicttomark readonly def
/csset % <cspace> csset <color> <cspace>
{ dup dup type /nametype ne { 0 get } if //CSdict exch get exec exch
} bdef
/g { //csdevgray fcput } bdef
/G { //csdevgray scput } bdef
/rg { 3 array astore cvx //csdevrgb fcput } bdef
/RG { 3 array astore cvx //csdevrgb scput } bdef
/k { 4 array astore cvx //csdevcmyk fcput } bdef
/K { 4 array astore cvx //csdevcmyk scput } bdef
/cs { csset fcput } bdef
/CS { csset scput } bdef
/ri { //.renderingintentdict exch .knownget { .setrenderingintent } if } bdef
% We have to break up sc according to the number of operands.
/sc1 { /FillColor gput } bdef
/SC1 { /StrokeColor gput } bdef
% We have to avoid storing into a color array associated with an outer
% gsave level, so we do a kind of "copy on write".
/sc* {
currentdict /FillColor .knownget {
astore pop
} {
/FillColor load
% FillColor may contain either a single value or an array.
dup type /arraytype eq { length }{ pop 1 } ifelse
array astore cvx /FillColor gput
} ifelse
} bdef
/SC* {
currentdict /StrokeColor .knownget {
astore pop
} {
/StrokeColor load
% StrokeColor may contain either a single value or an array.
dup type /arraytype eq { length }{ pop 1 } ifelse
array astore cvx /StrokeColor gput
} ifelse
} bdef
% ---------------- Overprint/transparency setting ---------------- %
/op { /FillOverprint gput } bdef
/OP { /StrokeOverprint gput } bdef
/OPM {
/.setoverprintmode where { pop dup .setoverprintmode .swapcolors .setoverprintmode .swapcolors } { pop } ifelse
} bdef
/ca { /FillConstantAlpha gput } bdef
/CA { /StrokeConstantAlpha gput } bdef
/SMask { /SoftMask gput } bdef
/AIS { /AlphaIsShape gput } bdef
/BM {
/.setblendmode where {
pop [ exch dup type /nametype ne { aload pop } if /Normal ] {
{ .setblendmode } .internalstopped not { exit } if pop
} forall
} {
pop
} ifelse
} bdef
/TK {
/.settextknockout where { pop .settextknockout } { pop } ifelse
} bdef
% ---------------- Color installation ---------------- %
% Establish a given color (and color space) as current.
/.settransparencyparams { % <alpha> <smask> .settransparencyparams -
PDFusingtransparency {
/.begintransparencygroup where {
pop AlphaIsShape {
1 .setopacityalpha exch .setshapealpha 1
} {
1 .setshapealpha exch .setopacityalpha 0
} ifelse
% Set the soft mask by rendering the XObject. Doing this every time
% is obviously very inefficient; we'll improve it later.
.settransparencymask
} {
pop pop
} ifelse
} {
pop pop
} ifelse
} bdef
/.settransparencymask { % <paramdict> <masknum> .settransparencymask -
exch dup //null eq {
PDFusingtransparency {
pop pop
} {
dup /Draw get exec
} ifelse
} {
dup /Draw get exec
} ifelse
} bdef
% (Non-mask) images must execute setfillblend.
/setfillblend {
FillOverprint setoverprint
FillConstantAlpha SoftMask .settransparencyparams
} def
/setfillstate {
FillColor FillColorSpace setgcolor setfillblend
} def
/setstrokestate {
.swapcolors
StrokeColor StrokeColorSpace setgcolor StrokeOverprint setoverprint
StrokeConstantAlpha SoftMask .settransparencyparams
.swapcolors
} def
/Cdict 15 dict dup begin % <color...> <colorspace> -proc- -
/DeviceGray { pop setgray } bdef
/DeviceRGB { pop setrgbcolor } bdef
/DeviceCMYK { pop setcmykcolor } bdef
/CIEBasedA { setgcolorspace setcolor } bdef
/CIEBasedABC /CIEBasedA load def
/CIEBasedDEF /CIEBasedA load def
/CIEBasedDEFG /CIEBasedA load def
/CalRGB /CIEBasedA load def
/CalGray /CIEBasedA load def
/Lab /CIEBasedA load def
/ICCBased /CIEBasedA load def
/Separation /CIEBasedA load def
/DeviceN /CIEBasedA load def
/Indexed /CIEBasedA load def
/Pattern
{ setgcolorspace
% Since multiple patterns may share
% same data stream, we need to ensure
% that the stream is at 0 position.
% Making this consistently with resolveshading,
% which applies ReusableStreamDecode filter
% to the PS stream, which represents the
% PDF stream in dynamics.
dup /Shading knownoget {
dup /ShadingType oget 4 ge {
/DataSource knownoget {
dup type /filetype eq {
0 setfileposition
} {
pop
} ifelse
} if
} {
pop
} ifelse
} if
% Associate pattern instance with the default qstate for the context.
% A single pattren object can be reused in several contexts.
dup DefaultQstate .knownget {
exch pop
} {
% But don't update read-only initial null pattern.
dup /PaintProc .knownget { //nullpatternproc ne } { //true } ifelse {
dup dup /Matrix knownoget not { { 1 0 0 1 0 0 } } if
gsave DefaultQstate setqstate makepattern grestore
dup 3 1 roll
DefaultQstate exch put
} if
} ifelse
setcolor
} bdef
end def
/setgcolor % (null | <color...>) <colorspace> setgcolor -
{ 1 index //null eq
{ pop pop }
{ dup 0 get //Cdict exch get exec }
ifelse
} bdef
% Compare the old and new color spaces in an attempt to avoid expensive
% reloads of CIEBased color spaces.
/PCSdict 15 dict dup begin % <colorspace> -proc- <colorspace|pdfcspace>
/CIEBasedA { dup 1 get /PDFColorSpace .knownget { exch pop } if } bdef
/CIEBasedABC /CIEBasedA load def
/CIEBasedDEF /CIEBasedA load def
/CIEBasedDEFG /CIEBasedA load def
/Indexed {
dup 1 get dup pdfcolorspace 2 copy ne { 3 1 roll } if pop pop
} bdef
end def
/pdfcolorspace { % <colorspace> pdfcolorspace <colorspace|pdfcspace>
dup type /arraytype eq {
//PCSdict 1 index 0 get .knownget { exec } if
} if
} bdef
/setgcolorspace { % <colorspace> setgcolorspace -
dup pdfcolorspace currentcolorspace pdfcolorspace eq {
pop
} {
setcolorspace
} ifelse
} bdef
/fsexec % <fillop|strokeop> fsexec -
{
SoftMask //null ne {
mark /Subtype /Group /Isolated //true .dicttomark pathbbox .begintransparencygroup
} if
cvx exec
SoftMask //null ne {
.endtransparencygroup
} if
} bdef
% ---------------- Path painting and clipping ---------------- %
/S {
OFFlevels length 0 eq {
setstrokestate .swapcolors /stroke fsexec .swapcolors
} {
newpath
} ifelse
} bdef
/f {
OFFlevels length 0 eq {
setfillstate /fill fsexec
} {
newpath
} ifelse
} bdef
/f* {
OFFlevels length 0 eq {
setfillstate /eofill fsexec
} {
newpath
} ifelse
} bdef
/n { newpath } bdef % don't allow n to get bound in
/s { closepath S } bdef
/B {
OFFlevels length 0 eq {
PDFusingtransparency {
% knockout trans group around the filled and stroked object
mark
/Isolated //true /Knockout //true
.dicttomark
% strokepath will return empty path (no currentpoint) if nothing is stroked
gsave { strokepath pathbbox } stopped grestore not {
1 .setopacityalpha
.begintransparencygroup
gsave setfillstate fill grestore
setstrokestate .swapcolors /stroke fsexec .swapcolors
.endtransparencygroup
} { newpath pop } ifelse
} {
gsave setfillstate fill grestore
setstrokestate .swapcolors /stroke fsexec .swapcolors
} ifelse
} {
newpath
} ifelse
} bdef
/b { closepath B } bdef
/B* {
OFFlevels length 0 eq {
PDFusingtransparency {
% knockout trans group around the filled and stroked object
mark
/Isolated //true /Knockout //true
.dicttomark
% strokepath will return empty path (no currentpoint) if nothing is stroked
gsave { strokepath pathbbox } stopped grestore not {
1 .setopacityalpha
.begintransparencygroup
gsave setfillstate eofill grestore
setstrokestate .swapcolors /stroke fsexec .swapcolors
.endtransparencygroup
} { newpath pop } ifelse
} {
gsave setfillstate eofill grestore
setstrokestate .swapcolors /stroke fsexec .swapcolors
} ifelse
} {
newpath
} ifelse
} bdef
/b* { closepath B* } bdef
% Clipping:
/Wdict 4 dict dup begin
/S { OFFlevels length 0 eq { gsave setstrokestate .swapcolors stroke .swapcolors grestore } if n } bdef
/f { OFFlevels length 0 eq { gsave setfillstate fill grestore } if n } bdef
/f* { OFFlevels length 0 eq { gsave setfillstate eofill grestore } if n } bdef
/n { end { currentpoint } stopped not { pop pop clip } if newpath } bdef
end readonly def
/W { //Wdict begin } bdef
/W*dict 4 dict dup begin
Wdict { def } forall
/n { end { currentpoint } stopped not { pop pop eoclip } if newpath } bdef
end readonly def
/W* { //W*dict begin } bdef
% ---------------- Text control ---------------- %
/textbeginpage
{ /TextSpacing 0 def % 0 Tc
/TextLeading 0 def % 0 TL
/TextRenderingMode 0 def % 0 Tr
/TextRise 0 def % 0 Ts
/WordSpacing 0 def % 0 Tw
/TextHScaling 1.0 def % 100 Tz
/TextFont //null def
/FontMatrixNonHV //false def
/Show { showfirst } def
} bdef
% Contrary to the statement in the PDF manual, BT and ET *can* be nested,
% if the CharProc for a Type 3 font does a BT/ET itself.
% Since we always call the CharProc inside a q/Q, we simply ensure that
% the text state is saved and restored like the rest of the extended
% graphics state.
/settextmatrix {
TextMatrix concat
TextHScaling 1 ne { TextHScaling 1 scale } if
TextRise 0 ne { 0 TextRise translate } if
TextFont dup //null eq { pop } { setfont } ifelse
} bdef
/settextstate {
% The text state can be set even outside BT/ET.
currentdict /TextSaveMatrix known {
TextSaveMatrix setmatrix settextmatrix
} if
} bdef
/settextposition {
% Update the TextMatrix translation.
gsave TextSaveMatrix setmatrix
currentpoint TextRise sub TextMatrix 4 2 getinterval astore pop
% We would like to do "grestore currentpoint translate"
% here, but some PDF files set a singular text matrix
% (0 0 0 0 <x> <y> Tm), so we can't do this.
TextTempMatrix identmatrix setmatrix currentpoint
grestore
TextTempMatrix currentmatrix 4 2 getinterval astore pop
TextTempMatrix setmatrix
} bdef
/BT {
currentdict /TextLineMatrix .knownget
{ identmatrix pop TextMatrix identmatrix pop }
{ matrix /TextLineMatrix gput matrix /TextMatrix gput }
ifelse
{ showfirst } /Show gput
currentdict /TextSaveMatrix .knownget not {
matrix dup /TextSaveMatrix gput
} if currentmatrix pop settextmatrix
matrix /TextTempMatrix gput % see settextposition
} bdef
/ET {
TextRenderingMode 4 ge { .currentfilladjust 0 .setfilladjust clip newpath .setfilladjust} if
TextSaveMatrix setmatrix
currentdict /TextSaveMatrix undef
} bdef
/Tc { /TextSpacing gput { showfirst } /Show gput } bdef
/TL { /TextLeading gput } bdef
/Tr { dup .settextrenderingmode /TextRenderingMode gput { showfirst } /Show gput } bdef
/Ts { /TextRise gput settextstate } bdef
/Tw { /WordSpacing gput { showfirst } /Show gput } bdef
/Tz { 100 div /TextHScaling gput settextstate} bdef
% ---------------- Font control ---------------- %
% Test if the FontMatrix could transform a horizontal/vertical (depending
% on writing mode) advance vector in glyph space into one with a different
% direction in text space.
% - if FontMatrix = [a b c d tx ty], this condition translates to:
% b != 0 for horizontal writing mode
% c != 0 for vertical writing mode
% - when false, we automatically have wy/x == 0 in text space whenever wy/x == 0
% in glyph space, and can avoid the slow method that is otherwise necessary
% to implement zeroing wy/x cf PDF Ref 5.3.3 "Text space details"
% Worker procedure for testing a single font matrix
/?FontMatrixNonHV { % ?horz <<fontdict>> -- ?horz ?nonhv
/FontMatrix .knownget {
1 index { 1 } { 2 } ifelse get 0 ne
} {
//false
} ifelse
} bdef
% Worker procedure for recursive checking of font matrices
/?FontMatrixNonHV { % {self} ?horz <<font>> -- {self} ?horz ?nonhv
2 copy //?FontMatrixNonHV exec { % check the font's own FontMatrix
pop pop //true
} {
% look for descendents/ components
pop % {self} ?horz <<font>>
dup /FontType get
dup 0 eq { % Type 0: look into FDepVector
pop /FDepVector get 2 index % {self} ?horz [fonts..] {testproc}
} {
9 eq { % Type 9 (CIDFontType 0): check FDArray
/FDArray get //?FontMatrixNonHV
} { % all others: nothing more to check
pop {} {}
} ifelse
} ifelse
%stack: {self} ?horz [fonts..] {testproc}
//false 5 2 roll { % {testproc} false {self} ?horz <<subfont>>
4 index exec {
4 -1 roll pop //true 4 1 roll
exit
} if
} forall
%stack: {testproc} ?nonhv {self} ?horz
4 2 roll exch pop
} ifelse
} bdef
% Main procedure
/?FontMatrixNonHV { % <<rootfont>> -- ?nonhv
//?FontMatrixNonHV exch
% determine WMode
dup /WMode .knownget { 0 eq } { //true } ifelse % {proc} <<rootfont>> ?horz
exch
% call the worker procedure
//?FontMatrixNonHV exec
exch pop exch pop
} bdef
/Tf { % <font> <scale> Tf -
dup 0 eq {
(\n **** Warning: Invalid 0.0 font scale given for Tf ****\n)
pdfformaterror
pop 0.00000001 % handle invalid scale by using a really small value
} if
1 index type /dicttype ne {
selectfont currentfont
} {
dup 1 eq { pop } { scalefont } ifelse
}
ifelse
dup ?FontMatrixNonHV dup FontMatrixNonHV ne {
/FontMatrixNonHV gput
{ showfirst } /Show gput
} {
pop
} ifelse
/TextFont gput settextstate
} bdef
% Copy a font, removing its FID. If changed is true, also remove
% the UniqueID and XUID, if any. If the original dictionary doesn't have
% the keys being removed, don't copy it.
/.copyfontdict % <font> <changed> .copyfontdict <dict>
{ 1 index /FID known
1 index { 2 index /UniqueID known or 2 index /XUID known or } if
{ % We add 1 to the length just in case the original
% didn't have a FID.
exch dup length 1 add dict exch
{ % Stack: changed newfont key value
1 index /FID eq 4 index
{ 2 index /UniqueID eq or 2 index /XUID eq or }
if not { 3 copy put } if pop pop
}
forall exch
}
if pop
} bdef
% Insert a new Encoding or Metrics into a font if necessary.
% Return a possibly updated font, and a flag to indicate whether
% the font was actually copied.
/.updatefontmetrics { % <font> <Metrics|null> .updatefontmetrics
% <font'> <copied>
dup //null ne {
exch //true .copyfontdict dup /Metrics 4 -1 roll put //true
} {
pop //false
} ifelse
} bdef
/.updatefontencoding { % <font> <Encoding|null> .updatefontencoding
% <font'> <copied>
dup //null ne { dup 2 index /Encoding get ne } { //false } ifelse {
exch //false .copyfontdict dup /Encoding 4 -1 roll put //true
} {
pop //false
} ifelse
} bdef
% Duplicate keys in CharString dictionary according to GlyphMap: <</new_glyph /old_glyph>>
% We have to do this because PDF fonts can associate multiple widths with the same glyph
% but Metrics dictionary works by the glyph name.
/.update_charstring { % <font> <GlyphMap> .update_charstring <font'> <copied>
dup //null ne {
exch //true .copyfontdict % map font
dup dup /CharStrings get % map font font cstr
dup length % map font font cstr len
4 index length add % map font font cstr len+map_len
dict copy dup begin % map font font cstr'
/CharStrings exch put % map font
exch { % font /new /old
currentdict exch .knownget {
def
} {
currentdict /.notdef .knownget {
def
} {
pop
% The font has no .notdef.
% Could not resolve the conflict,
% but either the font is invalid or the glyph name is never used.
} ifelse
} ifelse
} forall
end //true
} {
pop //false
} ifelse
} bdef
/.updatefont { % <font> <Encoding|null> <Metrics|null> <GlyphMap|null>
% .updatefont <font'> <copied>
4 2 roll % <Metrics|null> <GlyphMap> <font> <Encoding|null>
.updatefontencoding % <Metrics|null> <GlyphMap> <font> bool
4 1 roll exch % bool <Metrics|null> <font> <GlyphMap>
.update_charstring % bool <Metrics|null> <font> bool
3 1 roll exch % bool bool <font> <Metrics|null>
.updatefontmetrics % bool bool <font> bool
4 2 roll or or % <font> is_copied
} bdef
% ---------------- Text positioning ---------------- %
/Td {
TextLineMatrix transform TextLineMatrix 4 2 getinterval astore pop
TextLineMatrix TextMatrix copy pop settextstate
} bdef
/TD { dup neg /TextLeading gput Td } bdef
/T* { 0 TextLeading neg Td } bdef
/Tm {
TextLineMatrix astore TextMatrix copy pop settextstate
} bdef
% ---------------- Text painting ---------------- %
/Vexch {
rootfont /WMode knownoget { 1 eq { exch } if } if
} bind def
/textrenderingprocs [ % (0 is handled specially)
% Painting-only modes
{ tf } { tS } { tB } { tn }
% Clipping modes
{ gsave tf grestore tW }
{ gsave tS grestore tW }
{ gsave tB grestore tW }
{ tW }
] readonly def
/pdfwrite_textrenderingprocs [
% Tr 0 - Fill
{ setfillstate show } bind
% Tr 1 - Stroke
{ currentlinewidth exch setstrokestate
% Need to set the stroke width to a value which gives the correct
% width under pdfwrite. Pdfwrite uses (in text mode) an identity
% CTM, so we need to calculate the stroke width which would result
% if the CTM had been unity.
currentlinewidth dup
matrix defaultmatrix idtransform TextSaveMatrix dtransform
abs 2 copy exch abs eq {
pop
}{
% non-square scaling reduces to Text matrix in pdfwrite , so
% we can ignore it. (wrong answer, but consistent)
pop pop currentlinewidth
}ifelse setlinewidth
show setlinewidth} bind
% Tr 2 - Fill then Stroke
{ currentlinewidth exch setstrokestate
% Need to set the stroke width to a value which gives the correct
% width under pdfwrite. Pdfwrite uses (in text mode) an identity
% CTM, so we need to calculate the stroke width which would result
% if the CTM had been unity.
currentlinewidth dup
matrix defaultmatrix idtransform TextSaveMatrix dtransform
abs 2 copy exch abs eq {
pop
}{
% non-square scaling reduces to Text matrix in pdfwrite , so
% we can ignore it. (wrong answer, but consistent)
pop pop currentlinewidth
}ifelse setlinewidth
setfillstate show setlinewidth} bind
% Tr 3 - Neither fill nor stroke
{ setfillstate show } bind
%
% pdfwrite emits all text inside a gsave/grestore pair. As
% a result we can't preserve any of the 'clip' modes, as the
% clip gets undone by the restore. We need to handle the clip
% separately.
%
% Tr 4 - Fill, add to clip
{ gsave 0 .settextrenderingmode
setfillstate dup show grestore //true charpath } bind
% Tr 5 - Stroke, add to clip
{ gsave 1 .settextrenderingmode
currentlinewidth dup
matrix defaultmatrix idtransform TextSaveMatrix dtransform
abs 2 copy exch abs eq {
pop
}{
% non-square scaling reduces to Text matrix in pdfwrite , so
% we can ignore it. (wrong answer, but consistent)
pop pop currentlinewidth
}ifelse setlinewidth
setstrokestate dup show grestore
//true charpath} bind
% Tr 6 - Fill, stroke, add to clip
{ gsave 2 .settextrenderingmode
currentlinewidth dup
matrix defaultmatrix idtransform TextSaveMatrix dtransform
abs 2 copy exch abs eq {
pop
}{
% non-square scaling reduces to Text matrix in pdfwrite , so
% we can ignore it. (wrong answer, but consistent)
pop pop currentlinewidth
}ifelse setlinewidth
setstrokestate setfillstate dup show grestore
//true charpath} bind
% Tr 7 - Add to clip
{ //true charpath} bind
] readonly def
/setstrokeforTrpreservation {
% Check to see if the current device supports Tr
currentdevice 1 dict dup /PreserveTrMode dup put .getdeviceparams
dup type /booleantype eq not {cleartomark //false}{3 1 roll cleartomark}ifelse
{
TextRenderingMode 1 eq TextRenderingMode 2 eq or
TextRenderingMode 5 eq TextRenderingMode 6 eq or or {
setstrokestate
% Need to set the stroke width to a value which gives the correct
% width under pdfwrite. Pdfwrite uses (in text mode) an identity
% CTM, so we need to calculate the stroke width which would result
% if the CTM had been unity. NOTE! Only interested in magnitudes,
% not signs.
currentlinewidth dup
matrix defaultmatrix idtransform TextSaveMatrix dtransform
abs 2 copy exch abs eq {
pop
}{
% non-square scaling reduces to Text matrix in pdfwrite , so
% we can ignore it. (wrong answer, but consistent)
pop pop currentlinewidth
}ifelse
setlinewidth
} if
} if
} bind def
/setshowstate
{ WordSpacing 0 eq TextSpacing 0 eq and FontMatrixNonHV not and
{
% Check to see if the current device supports Tr
currentdevice 1 dict dup /PreserveTrMode dup put .getdeviceparams
dup type /booleantype eq not {cleartomark //false}{3 1 roll cleartomark}ifelse
{
pdfwrite_textrenderingprocs TextRenderingMode get
}
{
TextRenderingMode 0 eq {
{ setfillstate show }
} {
TextRenderingMode 3 eq {
% Some PDF files execute 'tm' with a singular matrix,
% and then use the text rendering mode 3.
% The graphics library currently cannot handle text
% operations when the CTM is singular.
% Work around this here.
{
matrix currentmatrix dup dup
dup 0 get 0 eq 1 index 1 get 0 eq and {
dup dup 2 get 0 eq { 0 }{ 1 } ifelse 1 put
} if
dup 2 get 0 eq 1 index 3 get 0 eq and {
dup dup 1 get 0 eq { 3 }{ 2 } ifelse 1 put
} if
setmatrix
currentpoint
4 index setfillstate show % Tr was set to graphic state.
moveto
setmatrix
% now set the currentpoint using the original matrix
gsave
setmatrix
//false charpath currentpoint newpath
grestore
moveto
}
} {
{ //false charpath textrenderingprocs TextRenderingMode get exec }
} ifelse
} ifelse
} ifelse
}
{
% If we are doing a plain old fill, or no text at all, *or* we are going to
% a device supporting text rendering modes, then go through this route.
%
TextRenderingMode 0 eq TextRenderingMode 3 eq or
currentdevice 1 dict dup /PreserveTrMode dup put .getdeviceparams
dup type /booleantype eq not {cleartomark //false}{3 1 roll cleartomark}ifelse
% pdfwrite can't handle rendering modes which involve clipping
TextRenderingMode 4 lt and or
% Tr was set to graphic state.
{
FontMatrixNonHV {
{
% preserve current line width around possible stroke setup
currentlinewidth exch
setstrokeforTrpreservation
setfillstate
[ TextSpacing WordSpacing 3 index
{ % str [... weach wword c undef|ythis xthis|undef
exch % will be removed, unless FontMatrix.xx/yy == 0 (FontMatrixNonHV already true)
Vexch pop % str [... weach wword c wthis
3 index add exch 32 eq {1 index add} if % str [... weach wword w
3 1 roll % str [... w weach wword
}
% for the "exch" removed or not below, see comment in pdf_font.ps::getfontmetrics
currentfont /FontMatrix get 0 3 Vexch pop get 0 ne {
1 1 index length 1 sub getinterval cvx
} if
cshow pop pop ]
{ xshow } { yshow } Vexch pop exec
setlinewidth
}
} {
WordSpacing 0 eq {
{
{ setstrokeforTrpreservation
setfillstate TextSpacing 0 Vexch 3 -1 roll ashow
}
currentlinewidth
{ setlinewidth }
3 .execn
}
} {
TextSpacing 0 eq {
{ % preserve current line width around possible stroke setup
{ setstrokeforTrpreservation
setfillstate WordSpacing 0 Vexch 32 4 -1 roll widthshow
}
currentlinewidth
{ setlinewidth }
3 .execn
}
} {
{ % preserve current line width around possible stroke setup
{ setstrokeforTrpreservation
setfillstate WordSpacing 0 Vexch 32
TextSpacing 0 Vexch 6 -1 roll awidthshow
}
currentlinewidth
{ setlinewidth }
3 .execn
}
} ifelse
} ifelse
} ifelse
}
{
{ currentlinewidth exch
WordSpacing TextSpacing
% Implement the combination of t3 and false charpath.
% Note that we must use cshow for this, because we
% can't parse multi-byte strings any other way.
% Stack: string wword wchar
{
exch % will be removed, unless FontMatrixNonHV && FontMatrix.xx/yy == 0
% Stack: str wword wchar ccode xthis ythis
Vexch pop currentpoint 6 3 roll
% Stack: str wthis xorig yorig wword wchar ccode
(x) dup 0 3 index put
%
% for devices which can handle the text rendering mode we don't want
% to decompose into paths, we want to do a 'show'. However pdfwrite
% can't handle clipping text, so we *do* want to do the clip path
% as a 'true charpath'.
%
currentdevice 1 dict dup /PreserveTrMode dup put .getdeviceparams
dup type /booleantype eq not {cleartomark //false}{3 1 roll cleartomark}ifelse {
% NB we must have Tr at least 4 or the test above would have
% taken a different path, so we *know* the Tr involves clipping
% or we wouldn't be here. Subtract 4 from the Tr and preserve
% that mode, then do a charpath so the clip path gets set up
% correctly.
gsave TextRenderingMode 4 sub .settextrenderingmode
setstrokeforTrpreservation
setstrokestate setfillstate dup show grestore} if
//false charpath
3 copy 32 eq { add } { exch pop } ifelse
% Stack: str wthis xorig yorig wword wchar ccode wextra
7 -3 roll moveto add
0 Vexch rmoveto pop
}
% for the "exch" removed or not below, see comment in pdf_font.ps::getfontmetrics
FontMatrixNonHV dup not exch {
currentfont /FontMatrix get 0 3 Vexch pop get 0 ne
} if {
1 1 index length 1 sub getinterval cvx
} if
4 -1 roll cshow pop pop
%
% If the device doesn't handle text rendering modes then we now have a suitable
% path, so call the correct routine to stroke/fill it (clip is handled when we
% get ET).
%
currentdevice 1 dict dup /PreserveTrMode dup put .getdeviceparams
dup type /booleantype eq not {cleartomark //false}{3 1 roll cleartomark}ifelse not {
textrenderingprocs TextRenderingMode get exec
} if
setlinewidth
}
}
ifelse
}
ifelse /Show gput
} bdef
/showfirst { setshowstate Show } def
/Tj {
{ 0 0 moveto Show settextposition }
OFFlevels length 0 eq {
exec
} {
gsave get-gs-attrs nulldevice set-gs-attrs
exec
get-gs-attrs grestore set-gs-attrs
} ifelse
} bdef
/' { T* Tj } bdef
/" { exch Tc exch Tw T* Tj } bdef
/TJ {
{ 0 0 moveto {
dup type /stringtype eq {
Show
} { -1000 div
currentfont /ScaleMatrix .knownget { 0 get mul } if
0 Vexch rmoveto
} ifelse
} forall settextposition
}
OFFlevels length 0 eq {
exec
} {
gsave get-gs-attrs nulldevice set-gs-attrs
exec
get-gs-attrs grestore set-gs-attrs
} ifelse
} bdef
/tf { setfillstate currentpoint fill moveto } bdef
/tn { currentpoint newpath moveto } bdef % Obsolete, never used.
% For stroking characters, temporarily restore the graphics CTM so that
% the line width will be transformed properly.
/Tmatrix matrix def
/tS
{ setstrokestate
currentpoint //Tmatrix currentmatrix TextSaveMatrix setmatrix .swapcolors stroke .swapcolors
setmatrix moveto
} bdef
% Handle transparency the same as /B operator
/tB {
PDFusingtransparency {
% knockout trans group around the filled and stroked object
mark
/Isolated //true /Knockout //true
.dicttomark
1 .setopacityalpha
% While text will always have a currentpoint, strokepath seems to mess with it.
% we get the currentpoint, then use moveto to restore it for pathbbox
gsave currentpoint strokepath moveto pathbbox grestore
.begintransparencygroup
gsave tf grestore tS
.endtransparencygroup
} {
gsave tf grestore tS
} ifelse
} bdef
% This does the wrong thing if there have been multiple text operations
% within a single BT/ET pair, but it's a start.
/tW { } bdef
% Text formatting and painting for the AcroForm field without appearance streams.
/Tform { % <MaxLen> (V) <Ff> <Q> Tform -
clippath pathbbox 4 2 roll pop pop % MaxLen (V) Ff Q dx dy
currentfont /ScaleMatrix .knownget { 3 get } { 1 } ifelse % MaxLen (V) Ff Q dx dy yy
currentfont /FontBBox get dup 1 get neg exch 3 get % MaxLen (V) Ff Q dx dy yy desc asc
dup 0 ne { div } { pop pop 0 } ifelse % MaxLen (V) Ff Q dx dy yy desc/asc
1 index mul % MaxLen (V) Ff Q dx dy yy desc/asc*yy
4 index 16#1000 and 0 ne { % multiline
8 { pop } repeat (Multiline form fields are not yet implemented.) =
} {
4 index 16#1000000 and 0 ne { % comb
8 { pop } repeat (Combed form fields are not yet implemented.) =
} { % plain text
3 1 roll sub add 2 div % MaxLen (V) Ff Q dx (dy-yy+desc)/2
0 exch moveto % MaxLen (V) Ff Q dx
1 index 0 ne {
3 index stringwidth pop % MaxLen (V) Ff Q dx w
sub exch 1 eq { 2 div } { 2 sub } ifelse % MaxLen (V) Ff (dx-w)/2
0 rmoveto % MaxLen (V) Ff
pop % MaxLen (V)
} {
pop pop pop % MaxLen (V)
2 0 rmoveto
} ifelse
exch pop Show % -
} ifelse
} ifelse
} bdef
end readonly put % GS_PDF_ProcSet
.setglobal
|