2 |
- |
1 |
% Copyright (C) 1994, 2000 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: pdf_ops.ps,v 1.41 2005/09/28 04:33:27 dan Exp $
|
|
|
17 |
% Definitions for most of the PDF operators.
|
|
|
18 |
|
|
|
19 |
.currentglobal true .setglobal
|
|
|
20 |
|
|
|
21 |
% Define pdfmark. Don't allow it to be bound in.
|
|
|
22 |
% Also don't define it in systemdict, because this leads some Adobe code
|
|
|
23 |
% to think this interpreter is a distiller.
|
|
|
24 |
% (If this interpreter really is a distiller, don't do this.)
|
|
|
25 |
systemdict /pdfmark known not
|
|
|
26 |
{ userdict /pdfmark { cleartomark } bind put } if
|
|
|
27 |
|
|
|
28 |
userdict /GS_PDF_ProcSet 127 dict dup begin
|
|
|
29 |
|
|
|
30 |
% ---------------- Abbreviations ---------------- %
|
|
|
31 |
|
|
|
32 |
/bdef { bind def } bind def
|
|
|
33 |
|
|
|
34 |
% ---------------- Graphics state stack ---------------- %
|
|
|
35 |
|
|
|
36 |
% PDF adds a number of parameters to the graphics state.
|
|
|
37 |
% We implement this by pushing and popping a dictionary
|
|
|
38 |
% each time we do a PDF gsave or grestore.
|
|
|
39 |
% The keys in this dictionary are as follows:
|
|
|
40 |
% self % identifies the dictionary as one of ours
|
|
|
41 |
% ClipRect % (optional)
|
|
|
42 |
% Show
|
|
|
43 |
% TextSaveMatrix % matrix at time of BT (iff within BT/ET)
|
|
|
44 |
% (The following correspond directly to PDF state parameters.)
|
|
|
45 |
% AlphaIsShape
|
|
|
46 |
% FillConstantAlpha
|
|
|
47 |
% FillColor
|
|
|
48 |
% FillColorSpace
|
|
|
49 |
% FillOverprint
|
|
|
50 |
% SoftMask
|
|
|
51 |
% StrokeConstantAlpha
|
|
|
52 |
% StrokeColor
|
|
|
53 |
% StrokeColorSpace
|
|
|
54 |
% StrokeOverprint
|
|
|
55 |
% TextSpacing
|
|
|
56 |
% TextHScaling
|
|
|
57 |
% Leading
|
|
|
58 |
% TextFont
|
|
|
59 |
% TextLineMatrix
|
|
|
60 |
% TextMatrix
|
|
|
61 |
% TextRise
|
|
|
62 |
% TextRenderingMode
|
|
|
63 |
% WordSpacing
|
|
|
64 |
|
|
|
65 |
/nodict 1 dict def
|
|
|
66 |
nodict /self { //nodict } executeonly put
|
|
|
67 |
nodict readonly pop
|
|
|
68 |
|
|
|
69 |
/dictbeginpage { % <initialdict> dictbeginpage -
|
|
|
70 |
//nodict 20 dict .copydict begin { def } forall
|
|
|
71 |
graphicsbeginpage textbeginpage
|
|
|
72 |
} bdef
|
|
|
73 |
/endpage { % - endpage -
|
|
|
74 |
showpage end
|
|
|
75 |
} bdef
|
|
|
76 |
|
|
|
77 |
/graphicsbeginpage {
|
|
|
78 |
initgraphics
|
|
|
79 |
currentdict /ClipRect knownoget { aload pop rectclip } if
|
|
|
80 |
|
|
|
81 |
1 ca 1 CA null SMask false AIS /Compatible BM true TK
|
|
|
82 |
} bdef
|
|
|
83 |
|
|
|
84 |
/gput % <value> <key> gput -
|
|
|
85 |
{ exch currentdict //nodict eq { /self dup load end 5 dict begin def } if
|
|
|
86 |
% If we're in a Level 1 system, we need to grow the
|
|
|
87 |
% dictionary explicitly.
|
|
|
88 |
currentdict length currentdict maxlength ge %eq
|
|
|
89 |
{ currentdict dup length 3 mul 2 idiv 1 add dict .copydict end begin
|
|
|
90 |
}
|
|
|
91 |
if def
|
|
|
92 |
} bdef
|
|
|
93 |
|
|
|
94 |
% Restore graphics state, but do not modify path. Paths are not part
|
|
|
95 |
% of the PDF graphics state; see 4.4.1 of PDF reference 3rd ed.
|
|
|
96 |
/grestore_nopath {
|
|
|
97 |
% Collect the upath with an identity CTM
|
|
|
98 |
{ matrix setmatrix //false upath } stopped {
|
|
|
99 |
pop grestore newpath
|
|
|
100 |
} {
|
|
|
101 |
% Save the CTM, set identity during the uappend, then set the CTM
|
|
|
102 |
grestore matrix currentmatrix matrix setmatrix
|
|
|
103 |
exch newpath uappend setmatrix
|
|
|
104 |
} ifelse
|
|
|
105 |
} bdef
|
|
|
106 |
|
|
|
107 |
/q {
|
|
|
108 |
gsave //nodict begin
|
|
|
109 |
} bdef
|
|
|
110 |
% Some PDF files have excess Q operators!
|
|
|
111 |
/Q {
|
|
|
112 |
currentdict /self .knownget {
|
|
|
113 |
exec //nodict eq { end grestore_nopath false } { true } ifelse
|
|
|
114 |
} {
|
|
|
115 |
true % formaterror -- not a gsave dict
|
|
|
116 |
} ifelse
|
|
|
117 |
{ (\n **** File has imbalanced q/Q operators \(too many Q's\) ****\n)
|
|
|
118 |
pdfformaterror
|
|
|
119 |
} if
|
|
|
120 |
} bdef
|
|
|
121 |
|
|
|
122 |
% Save PDF gstate
|
|
|
123 |
/qstate { % - qstate <qstate>
|
|
|
124 |
gstate
|
|
|
125 |
} bdef
|
|
|
126 |
|
|
|
127 |
% Set PDF gstate
|
|
|
128 |
/setqstate { % <qstate> setqstate -
|
|
|
129 |
{ matrix setmatrix //false upath } stopped {
|
|
|
130 |
pop setgstate newpath
|
|
|
131 |
} {
|
|
|
132 |
% Save the CTM, set identity during the uappend, then set the CTM
|
|
|
133 |
exch setgstate matrix currentmatrix matrix setmatrix
|
|
|
134 |
exch newpath uappend setmatrix
|
|
|
135 |
} ifelse
|
|
|
136 |
} bdef
|
|
|
137 |
|
|
|
138 |
% ---------------- Color setting ---------------- %
|
|
|
139 |
|
|
|
140 |
/fcput % <color> <colorspace> fcput -
|
|
|
141 |
{ /FillColorSpace gput /FillColor gput
|
|
|
142 |
} bdef
|
|
|
143 |
/scput % <color> <colorspace> scput -
|
|
|
144 |
{ /StrokeColorSpace gput /StrokeColor gput
|
|
|
145 |
} bdef
|
|
|
146 |
/csput % <colorspace> csput -
|
|
|
147 |
{ csset 2 copy fcput scput
|
|
|
148 |
} bdef
|
|
|
149 |
|
|
|
150 |
/csdevgray [/DeviceGray] readonly def
|
|
|
151 |
/csdevrgb [/DeviceRGB] readonly def
|
|
|
152 |
/csdevcmyk [/DeviceCMYK] readonly def
|
|
|
153 |
/cspattern [/Pattern] readonly def
|
|
|
154 |
/nullpattern1 mark
|
|
|
155 |
/PatternType 1 /PaintType 1 /TilingType 3 /BBox [0 0 0 0]
|
|
|
156 |
/XStep 1 /YStep 1 /PaintProc { }
|
|
|
157 |
.dicttomark readonly def
|
|
|
158 |
/nullpattern2 nullpattern1 dup length dict copy readonly def
|
|
|
159 |
|
|
|
160 |
% Each entry in the color space dictionary is a procedure of the form
|
|
|
161 |
% <cspace> -proc- <cspace> <initial-color>
|
|
|
162 |
/CSdict mark
|
|
|
163 |
/DeviceGray { pop //csdevgray 0 } bind
|
|
|
164 |
/DeviceRGB { pop //csdevrgb [0 0 0] cvx } bind
|
|
|
165 |
/DeviceCMYK { pop //csdevcmyk [0 0 0 1] cvx } bind
|
|
|
166 |
/CIEBasedA { 0 } bind
|
|
|
167 |
/CIEBasedABC { [0 0 0] cvx } bind
|
|
|
168 |
/ICCBased { [ 1 index 1 oget /N get { 0 } repeat ] cvx } bind
|
|
|
169 |
/Separation { 1 } bind
|
|
|
170 |
/DeviceN { % What is the correct value??
|
|
|
171 |
[ 1 index 1 get length { 1 } repeat ] cvx
|
|
|
172 |
} bind
|
|
|
173 |
/Indexed { 0 } bind
|
|
|
174 |
/Pattern {
|
|
|
175 |
dup type /nametype eq 1 index length 1 eq or {
|
|
|
176 |
pop //cspattern //nullpattern1 matrix makepattern
|
|
|
177 |
} {
|
|
|
178 |
//nullpattern2 matrix makepattern 1 index 1 get csset
|
|
|
179 |
% Stack: patternspace nullpattern basecolor basespace
|
|
|
180 |
pop [ 3 1 roll dup type /arraytype eq { aload pop } if
|
|
|
181 |
counttomark -1 roll ] cvx
|
|
|
182 |
} ifelse
|
|
|
183 |
} bind
|
|
|
184 |
.dicttomark readonly def
|
|
|
185 |
/csset % <cspace> csset <color> <cspace>
|
|
|
186 |
{ dup dup type /nametype ne { 0 get } if //CSdict exch get exec exch
|
|
|
187 |
} bdef
|
|
|
188 |
|
|
|
189 |
/g { //csdevgray fcput } bdef
|
|
|
190 |
/G { //csdevgray scput } bdef
|
|
|
191 |
/rg { 3 array astore cvx //csdevrgb fcput } bdef
|
|
|
192 |
/RG { 3 array astore cvx //csdevrgb scput } bdef
|
|
|
193 |
/k { 4 array astore cvx //csdevcmyk fcput } bdef
|
|
|
194 |
/K { 4 array astore cvx //csdevcmyk scput } bdef
|
|
|
195 |
/cs { csset fcput } bdef
|
|
|
196 |
/CS { csset scput } bdef
|
|
|
197 |
/ri { pop } bdef
|
|
|
198 |
% We have to break up sc according to the number of operands.
|
|
|
199 |
/sc1 { /FillColor gput } bdef
|
|
|
200 |
/SC1 { /StrokeColor gput } bdef
|
|
|
201 |
% We have to avoid storing into a color array associated with an outer
|
|
|
202 |
% gsave level, so we do a kind of "copy on write".
|
|
|
203 |
/sc* {
|
|
|
204 |
currentdict /FillColor .knownget {
|
|
|
205 |
astore pop
|
|
|
206 |
} {
|
|
|
207 |
/FillColor load
|
|
|
208 |
% FillColor may contain either a single value or an array.
|
|
|
209 |
dup type /arraytype eq { length }{ pop 1 } ifelse
|
|
|
210 |
array astore cvx /FillColor gput
|
|
|
211 |
} ifelse
|
|
|
212 |
} bdef
|
|
|
213 |
/SC* {
|
|
|
214 |
currentdict /StrokeColor .knownget {
|
|
|
215 |
astore pop
|
|
|
216 |
} {
|
|
|
217 |
/StrokeColor load
|
|
|
218 |
% StrokeColor may contain either a single value or an array.
|
|
|
219 |
dup type /arraytype eq { length }{ pop 1 } ifelse
|
|
|
220 |
array astore cvx /StrokeColor gput
|
|
|
221 |
} ifelse
|
|
|
222 |
} bdef
|
|
|
223 |
|
|
|
224 |
% ---------------- Overprint/transparency setting ---------------- %
|
|
|
225 |
|
|
|
226 |
/op { /FillOverprint gput } bdef
|
|
|
227 |
/OP { /StrokeOverprint gput } bdef
|
|
|
228 |
/OPM {
|
|
|
229 |
/.setoverprintmode where { pop .setoverprintmode } { pop } ifelse
|
|
|
230 |
} bdef
|
|
|
231 |
/ca { /FillConstantAlpha gput } bdef
|
|
|
232 |
/CA { /StrokeConstantAlpha gput } bdef
|
|
|
233 |
/SMask { /SoftMask gput } bdef
|
|
|
234 |
/AIS { /AlphaIsShape gput } bdef
|
|
|
235 |
/BM {
|
|
|
236 |
/.setblendmode where {
|
|
|
237 |
pop [ exch dup type /nametype ne { aload pop } if /Normal ] {
|
|
|
238 |
{ .setblendmode } .internalstopped not { exit } if pop
|
|
|
239 |
} forall
|
|
|
240 |
} {
|
|
|
241 |
pop
|
|
|
242 |
} ifelse
|
|
|
243 |
} bdef
|
|
|
244 |
/TK {
|
|
|
245 |
/.settextknockout where { pop .settextknockout } { pop } ifelse
|
|
|
246 |
} bdef
|
|
|
247 |
|
|
|
248 |
% ---------------- Color installation ---------------- %
|
|
|
249 |
|
|
|
250 |
% Establish a given color (and color space) as current.
|
|
|
251 |
/.settransparencyparams { % <alpha> <smask> .settransparencyparams -
|
|
|
252 |
/.inittransparencymask where {
|
|
|
253 |
pop AlphaIsShape {
|
|
|
254 |
1 .setopacityalpha 0 .inittransparencymask exch .setshapealpha 1
|
|
|
255 |
} {
|
|
|
256 |
1 .setshapealpha 1 .inittransparencymask exch .setopacityalpha 0
|
|
|
257 |
} ifelse
|
|
|
258 |
% Set the soft mask by rendering the XObject. Doing this every time
|
|
|
259 |
% is obviously very inefficient; we'll improve it later.
|
|
|
260 |
.settransparencymask
|
|
|
261 |
} {
|
|
|
262 |
pop pop
|
|
|
263 |
} ifelse
|
|
|
264 |
} bdef
|
|
|
265 |
/.settransparencymask { % <paramdict> <masknum> .settransparencymask -
|
|
|
266 |
exch dup null eq {
|
|
|
267 |
pop .inittransparencymask
|
|
|
268 |
} {
|
|
|
269 |
dup /Draw get exec
|
|
|
270 |
} ifelse
|
|
|
271 |
} bdef
|
|
|
272 |
% (Non-mask) images must execute setfillblend.
|
|
|
273 |
/setfillblend {
|
|
|
274 |
FillOverprint setoverprint
|
|
|
275 |
FillConstantAlpha SoftMask .settransparencyparams
|
|
|
276 |
} def
|
|
|
277 |
/setfillstate {
|
|
|
278 |
FillColor FillColorSpace setgcolor setfillblend
|
|
|
279 |
} def
|
|
|
280 |
/setstrokestate {
|
|
|
281 |
StrokeColor StrokeColorSpace setgcolor StrokeOverprint setoverprint
|
|
|
282 |
StrokeConstantAlpha SoftMask .settransparencyparams
|
|
|
283 |
} def
|
|
|
284 |
/Cdict 15 dict dup begin % <color...> <colorspace> -proc- -
|
|
|
285 |
/DeviceGray { pop setgray } bdef
|
|
|
286 |
/DeviceRGB { pop setrgbcolor } bdef
|
|
|
287 |
/DeviceCMYK { pop setcmykcolor } bdef
|
|
|
288 |
/CIEBasedA { setgcolorspace setcolor } bdef
|
|
|
289 |
/CIEBasedABC /CIEBasedA load def
|
|
|
290 |
/CIEBasedDEF /CIEBasedA load def
|
|
|
291 |
/CIEBasedDEFG /CIEBasedA load def
|
|
|
292 |
/ICCBased /CIEBasedA load def
|
|
|
293 |
/Separation /CIEBasedA load def
|
|
|
294 |
/DeviceN /CIEBasedA load def
|
|
|
295 |
/Indexed /CIEBasedA load def
|
|
|
296 |
/Pattern
|
|
|
297 |
{ setgcolorspace
|
|
|
298 |
|
|
|
299 |
% Since multiple patterns may share
|
|
|
300 |
% same data stream, we need to ensure
|
|
|
301 |
% that the stream is at 0 position.
|
|
|
302 |
% Making this consistently with resolveshading,
|
|
|
303 |
% which applies ReusableStreamDecode filter
|
|
|
304 |
% to the PS stream, which represents the
|
|
|
305 |
% PDF stream in dynamics.
|
|
|
306 |
|
|
|
307 |
dup /Shading knownoget {
|
|
|
308 |
dup /ShadingType oget 4 ge {
|
|
|
309 |
/DataSource knownoget {
|
|
|
310 |
dup type /filetype eq {
|
|
|
311 |
|
|
|
312 |
} {
|
|
|
313 |
pop
|
|
|
314 |
} ifelse
|
|
|
315 |
} if
|
|
|
316 |
} {
|
|
|
317 |
pop
|
|
|
318 |
} ifelse
|
|
|
319 |
} if
|
|
|
320 |
|
|
|
321 |
dup /Matrix knownoget not { matrix } if
|
|
|
322 |
gsave DefaultQstate setqstate makepattern grestore setcolor
|
|
|
323 |
} bdef
|
|
|
324 |
end def
|
|
|
325 |
/setgcolor % (null | <color...>) <colorspace> setgcolor -
|
|
|
326 |
{ 1 index null eq
|
|
|
327 |
{ pop pop }
|
|
|
328 |
{ dup 0 get //Cdict exch get exec }
|
|
|
329 |
ifelse
|
|
|
330 |
} bdef
|
|
|
331 |
% Compare the old and new color spaces in an attempt to avoid expensive
|
|
|
332 |
% reloads of CIEBased color spaces.
|
|
|
333 |
/PCSdict 15 dict dup begin % <colorspace> -proc- <colorspace|pdfcspace>
|
|
|
334 |
/CIEBasedA { dup 1 get /PDFColorSpace .knownget { exch pop } if } bdef
|
|
|
335 |
/CIEBasedABC /CIEBasedA load def
|
|
|
336 |
/CIEBasedDEF /CIEBasedA load def
|
|
|
337 |
/CIEBasedDEFG /CIEBasedA load def
|
|
|
338 |
/Indexed {
|
|
|
339 |
dup 1 get dup pdfcolorspace 2 copy ne { 3 1 roll } if pop pop
|
|
|
340 |
} bdef
|
|
|
341 |
end def
|
|
|
342 |
/pdfcolorspace { % <colorspace> pdfcolorspace <colorspace|pdfcspace>
|
|
|
343 |
dup type /arraytype eq {
|
|
|
344 |
//PCSdict 1 index 0 get .knownget { exec } if
|
|
|
345 |
} if
|
|
|
346 |
} bdef
|
|
|
347 |
/setgcolorspace { % <colorspace> setgcolorspace -
|
|
|
348 |
dup pdfcolorspace currentcolorspace pdfcolorspace eq {
|
|
|
349 |
pop
|
|
|
350 |
} {
|
|
|
351 |
setcolorspace
|
|
|
352 |
} ifelse
|
|
|
353 |
} bdef
|
|
|
354 |
/fsexec % <fillop|strokeop> fsexec -
|
|
|
355 |
{ % Preserve the current point, if any.
|
|
|
356 |
{ currentpoint } stopped
|
|
|
357 |
{ $error /newerror false put cvx exec }
|
|
|
358 |
{ 3 -1 roll cvx exec moveto }
|
|
|
359 |
ifelse
|
|
|
360 |
} bdef
|
|
|
361 |
|
|
|
362 |
% ---------------- Path painting and clipping ---------------- %
|
|
|
363 |
|
|
|
364 |
/S { setstrokestate /stroke fsexec } bdef
|
|
|
365 |
/f { setfillstate /fill fsexec } bdef
|
|
|
366 |
/f* { setfillstate /eofill fsexec } bdef
|
|
|
367 |
/n { newpath } bdef % don't allow n to get bound in
|
|
|
368 |
/s { closepath S } bdef
|
|
|
369 |
/B { gsave setfillstate fill grestore S } bdef
|
|
|
370 |
/b { closepath B } bdef
|
|
|
371 |
/B* { gsave setfillstate eofill grestore S } bdef
|
|
|
372 |
/b* { closepath B* } bdef
|
|
|
373 |
|
|
|
374 |
% Clipping:
|
|
|
375 |
|
|
|
376 |
/Wdict 4 dict dup begin
|
|
|
377 |
/S { gsave setstrokestate stroke grestore n } bdef
|
|
|
378 |
/f { gsave setfillstate fill grestore n } bdef
|
|
|
379 |
/f* { gsave setfillstate eofill grestore n } bdef
|
|
|
380 |
/n { end clip newpath } bdef
|
|
|
381 |
end readonly def
|
|
|
382 |
/W { //Wdict begin } bdef
|
|
|
383 |
/W*dict 4 dict dup begin
|
|
|
384 |
Wdict { def } forall
|
|
|
385 |
/n { end eoclip newpath } bdef
|
|
|
386 |
end readonly def
|
|
|
387 |
/W* { //W*dict begin } bdef
|
|
|
388 |
|
|
|
389 |
% ---------------- Text control ---------------- %
|
|
|
390 |
|
|
|
391 |
/textbeginpage
|
|
|
392 |
{ /TextSpacing 0 def % 0 Tc
|
|
|
393 |
/TextLeading 0 def % 0 TL
|
|
|
394 |
/TextRenderingMode 0 def % 0 Tr
|
|
|
395 |
/TextRise 0 def % 0 Ts
|
|
|
396 |
/WordSpacing 0 def % 0 Tw
|
|
|
397 |
/TextHScaling 1.0 def % 100 Tz
|
|
|
398 |
/TextFont null def
|
|
|
399 |
/Show { showfirst } def
|
|
|
400 |
} bdef
|
|
|
401 |
|
|
|
402 |
% Contrary to the statement in the PDF manual, BT and ET *can* be nested,
|
|
|
403 |
% if the CharProc for a Type 3 font does a BT/ET itself.
|
|
|
404 |
% Since we always call the CharProc inside a q/Q, we simply ensure that
|
|
|
405 |
% the text state is saved and restored like the rest of the extended
|
|
|
406 |
% graphics state.
|
|
|
407 |
|
|
|
408 |
/settextmatrix {
|
|
|
409 |
TextMatrix concat
|
|
|
410 |
TextHScaling 1 ne { TextHScaling 1 scale } if
|
|
|
411 |
TextRise 0 ne { 0 TextRise translate } if
|
|
|
412 |
TextFont dup null eq { pop } { setfont } ifelse
|
|
|
413 |
} bdef
|
|
|
414 |
/settextstate {
|
|
|
415 |
% The text state can be set even outside BT/ET.
|
|
|
416 |
currentdict /TextSaveMatrix known {
|
|
|
417 |
TextSaveMatrix setmatrix settextmatrix
|
|
|
418 |
} if
|
|
|
419 |
} bdef
|
|
|
420 |
/settextposition {
|
|
|
421 |
% Update the TextMatrix translation.
|
|
|
422 |
gsave TextSaveMatrix setmatrix
|
|
|
423 |
currentpoint TextRise sub TextMatrix 4 2 getinterval astore pop
|
|
|
424 |
% We would like to do "grestore currentpoint translate"
|
|
|
425 |
% here, but some PDF files set a singular text matrix
|
|
|
426 |
% (0 0 0 0 <x> <y> Tm), so we can't do this.
|
|
|
427 |
TextTempMatrix identmatrix setmatrix currentpoint
|
|
|
428 |
grestore
|
|
|
429 |
TextTempMatrix currentmatrix 4 2 getinterval astore pop
|
|
|
430 |
TextTempMatrix setmatrix
|
|
|
431 |
} bdef
|
|
|
432 |
|
|
|
433 |
/BT {
|
|
|
434 |
currentdict /TextLineMatrix .knownget
|
|
|
435 |
{ identmatrix pop TextMatrix identmatrix pop }
|
|
|
436 |
{ matrix /TextLineMatrix gput matrix /TextMatrix gput }
|
|
|
437 |
ifelse
|
|
|
438 |
{ showfirst } /Show gput
|
|
|
439 |
currentdict /TextSaveMatrix .knownget not {
|
|
|
440 |
matrix dup /TextSaveMatrix gput
|
|
|
441 |
} if currentmatrix pop settextmatrix
|
|
|
442 |
matrix /TextTempMatrix gput % see settextposition
|
|
|
443 |
} bdef
|
|
|
444 |
/ET {
|
|
|
445 |
TextRenderingMode 4 ge { clip newpath } if
|
|
|
446 |
TextSaveMatrix setmatrix
|
|
|
447 |
currentdict /TextSaveMatrix undef
|
|
|
448 |
} bdef
|
|
|
449 |
/Tc { /TextSpacing gput { showfirst } /Show gput } bdef
|
|
|
450 |
/TL { /TextLeading gput } bdef
|
|
|
451 |
/Tr { dup .settextrenderingmode /TextRenderingMode gput { showfirst } /Show gput } bdef
|
|
|
452 |
/Ts { /TextRise gput settextstate } bdef
|
|
|
453 |
/Tw { /WordSpacing gput { showfirst } /Show gput } bdef
|
|
|
454 |
/Tz { 100 div /TextHScaling gput settextstate} bdef
|
|
|
455 |
|
|
|
456 |
% ---------------- Font control ---------------- %
|
|
|
457 |
|
|
|
458 |
/Tf { % <font> <scale> Tf -
|
|
|
459 |
dup 0 eq {
|
|
|
460 |
(\n **** Warning: Invalid 0.0 font scale given for Tf ****\n)
|
|
|
461 |
pdfformaterror
|
|
|
462 |
pop 0.00000001 % handle invalid scale by using a really small value
|
|
|
463 |
} if
|
|
|
464 |
dup 1 eq { pop } { scalefont } ifelse
|
|
|
465 |
/TextFont gput settextstate
|
|
|
466 |
} bdef
|
|
|
467 |
|
|
|
468 |
% Read a CFF font.
|
|
|
469 |
/FRD % <resname> <file> FRD -
|
|
|
470 |
{ /FontSetInit /ProcSet findresource begin //true ReadData
|
|
|
471 |
} bdef
|
|
|
472 |
|
|
|
473 |
% Copy a font, removing its FID. If changed is true, also remove
|
|
|
474 |
% the UniqueID and XUID, if any. If the original dictionary doesn't have
|
|
|
475 |
% the keys being removed, don't copy it.
|
|
|
476 |
/.copyfontdict % <font> <changed> .copyfontdict <dict>
|
|
|
477 |
{ 1 index /FID known
|
|
|
478 |
1 index { 2 index /UniqueID known or 2 index /XUID known or } if
|
|
|
479 |
{ % We add 1 to the length just in case the original
|
|
|
480 |
% didn't have a FID.
|
|
|
481 |
exch dup length 1 add dict exch
|
|
|
482 |
{ % Stack: changed newfont key value
|
|
|
483 |
1 index /FID eq 4 index
|
|
|
484 |
{ 2 index /UniqueID eq or 2 index /XUID eq or }
|
|
|
485 |
if not { 3 copy put } if pop pop
|
|
|
486 |
}
|
|
|
487 |
forall exch
|
|
|
488 |
}
|
|
|
489 |
if pop
|
|
|
490 |
} bdef
|
|
|
491 |
|
|
|
492 |
% Insert a new Encoding or Metrics into a font if necessary.
|
|
|
493 |
% Return a possibly updated font, and a flag to indicate whether
|
|
|
494 |
% the font was actually copied.
|
|
|
495 |
/.updatefontmetrics { % <font> <Metrics|null> .updatefontmetrics
|
|
|
496 |
% <font'> <copied>
|
|
|
497 |
dup //null ne {
|
|
|
498 |
exch //true .copyfontdict dup /Metrics 4 -1 roll put //true
|
|
|
499 |
} {
|
|
|
500 |
pop //false
|
|
|
501 |
} ifelse
|
|
|
502 |
} bdef
|
|
|
503 |
|
|
|
504 |
/.updatefontencoding { % <font> <Encoding|null> .updatefontencoding
|
|
|
505 |
% <font'> <copied>
|
|
|
506 |
dup //null ne { dup 2 index /Encoding get ne } { //false } ifelse {
|
|
|
507 |
exch //false .copyfontdict dup /Encoding 4 -1 roll put //true
|
|
|
508 |
} {
|
|
|
509 |
pop //false
|
|
|
510 |
} ifelse
|
|
|
511 |
} bdef
|
|
|
512 |
|
|
|
513 |
% Duplicate keys in CharString dictionary according to GlyphMap: <</new_glyph /old_glyph>>
|
|
|
514 |
% We have to do this because PDF fonts can associate multiple widths with the same glyph
|
|
|
515 |
% but Metrics dictionary works by the glyph name.
|
|
|
516 |
/.update_charstring { % <font> <GlyphMap> .update_charstring <font'> <copied>
|
|
|
517 |
dup //null ne {
|
|
|
518 |
exch //true .copyfontdict % map font
|
|
|
519 |
dup dup /CharStrings get % map font font cstr
|
|
|
520 |
dup length % map font font cstr len
|
|
|
521 |
4 index length add % map font font cstr len+map_len
|
|
|
522 |
dict copy dup begin % map font font cstr'
|
|
|
523 |
/CharStrings exch put % map font
|
|
|
524 |
exch { % font /new /old
|
|
|
525 |
currentdict exch .knownget {
|
|
|
526 |
def
|
|
|
527 |
} {
|
|
|
528 |
currentdict /.notdef .knownget {
|
|
|
529 |
def
|
|
|
530 |
} {
|
|
|
531 |
pop
|
|
|
532 |
% The font has no .notdef.
|
|
|
533 |
% Could not resolve the conflict,
|
|
|
534 |
% but either the font is invalid or the glyph name is never used.
|
|
|
535 |
} ifelse
|
|
|
536 |
} ifelse
|
|
|
537 |
} forall
|
|
|
538 |
end //true
|
|
|
539 |
} {
|
|
|
540 |
pop //false
|
|
|
541 |
} ifelse
|
|
|
542 |
} bdef
|
|
|
543 |
|
|
|
544 |
/.updatefont { % <font> <Encoding|null> <Metrics|null> <GlyphMap|null>
|
|
|
545 |
% .updatefont <font'> <copied>
|
|
|
546 |
4 2 roll % <Metrics|null> <GlyphMap> <font> <Encoding|null>
|
|
|
547 |
.updatefontencoding % <Metrics|null> <GlyphMap> <font> bool
|
|
|
548 |
4 1 roll exch % bool <Metrics|null> <font> <GlyphMap>
|
|
|
549 |
.update_charstring % bool <Metrics|null> <font> bool
|
|
|
550 |
3 1 roll exch % bool bool <font> <Metrics|null>
|
|
|
551 |
.updatefontmetrics % bool bool <font> bool
|
|
|
552 |
4 2 roll or or % <font> is_copied
|
|
|
553 |
} bdef
|
|
|
554 |
|
|
|
555 |
% ---------------- Text positioning ---------------- %
|
|
|
556 |
|
|
|
557 |
/Td {
|
|
|
558 |
TextLineMatrix transform TextLineMatrix 4 2 getinterval astore pop
|
|
|
559 |
TextLineMatrix TextMatrix copy pop settextstate
|
|
|
560 |
} bdef
|
|
|
561 |
/TD { dup neg /TextLeading gput Td } bdef
|
|
|
562 |
/T* { 0 TextLeading neg Td } bdef
|
|
|
563 |
/Tm {
|
|
|
564 |
TextLineMatrix astore TextMatrix copy pop settextstate
|
|
|
565 |
} bdef
|
|
|
566 |
|
|
|
567 |
% ---------------- Text painting ---------------- %
|
|
|
568 |
|
|
|
569 |
/Vexch {
|
|
|
570 |
rootfont /WMode knownoget { 1 eq { exch } if } if
|
|
|
571 |
} bind def
|
|
|
572 |
|
|
|
573 |
/textrenderingprocs [ % (0 is handled specially)
|
|
|
574 |
% Painting-only modes
|
|
|
575 |
{ tf } { tS } { tB } { tn }
|
|
|
576 |
% Clipping modes
|
|
|
577 |
{ gsave tf grestore tW }
|
|
|
578 |
{ gsave tS grestore tW }
|
|
|
579 |
{ gsave tB grestore tW }
|
|
|
580 |
{ tW }
|
|
|
581 |
] readonly def
|
|
|
582 |
/setshowstate
|
|
|
583 |
{ WordSpacing 0 eq TextSpacing 0 eq and
|
|
|
584 |
{ TextRenderingMode 0 eq {
|
|
|
585 |
{ setfillstate show }
|
|
|
586 |
} {
|
|
|
587 |
TextRenderingMode 3 eq {
|
|
|
588 |
% Some PDF files execute 'tm' with a singular matrix,
|
|
|
589 |
% and then use the text rendering mode 3.
|
|
|
590 |
% The graphics library currently cannot handle text
|
|
|
591 |
% operations when the CTM is singular.
|
|
|
592 |
% Work around this here.
|
|
|
593 |
{
|
|
|
594 |
matrix currentmatrix dup
|
|
|
595 |
dup 0 get 0 eq 1 index 1 get 0 eq and {
|
|
|
596 |
dup dup 2 get 0 eq { 0 }{ 1 } ifelse 1 put
|
|
|
597 |
} if
|
|
|
598 |
dup 2 get 0 eq 1 index 3 get 0 eq and {
|
|
|
599 |
dup dup 1 get 0 eq { 3 }{ 2 } ifelse 1 put
|
|
|
600 |
} if
|
|
|
601 |
setmatrix
|
|
|
602 |
1 index setfillstate show % Tr was set to graphic state.
|
|
|
603 |
setmatrix
|
|
|
604 |
% now set the currentpoint using the original matrix
|
|
|
605 |
false charpath currentpoint newpath moveto
|
|
|
606 |
}
|
|
|
607 |
} {
|
|
|
608 |
{ false charpath textrenderingprocs TextRenderingMode get exec }
|
|
|
609 |
} ifelse
|
|
|
610 |
} ifelse
|
|
|
611 |
}
|
|
|
612 |
{ TextRenderingMode 0 eq TextRenderingMode 3 eq or
|
|
|
613 |
% Tr was set to graphic state.
|
|
|
614 |
{ WordSpacing 0 eq
|
|
|
615 |
{ { setfillstate TextSpacing 0 Vexch 3 -1 roll ashow } }
|
|
|
616 |
{ TextSpacing 0 eq
|
|
|
617 |
{ { setfillstate WordSpacing 0 Vexch 32 4 -1 roll widthshow } }
|
|
|
618 |
{ { setfillstate WordSpacing 0 Vexch 32
|
|
|
619 |
TextSpacing 0 Vexch 6 -1 roll awidthshow } }
|
|
|
620 |
ifelse
|
|
|
621 |
}
|
|
|
622 |
ifelse
|
|
|
623 |
}
|
|
|
624 |
{ { WordSpacing TextSpacing
|
|
|
625 |
% Implement the combination of t3 and false charpath.
|
|
|
626 |
% Note that we must use cshow for this, because we
|
|
|
627 |
% can't parse multi-byte strings any other way.
|
|
|
628 |
% Stack: string xword xchar
|
|
|
629 |
{ pop pop (x) dup 0 3 index put false charpath
|
|
|
630 |
% Stack: xword xchar ccode
|
|
|
631 |
3 copy 32 eq { add } { exch pop } ifelse 0 Vexch rmoveto pop
|
|
|
632 |
}
|
|
|
633 |
4 -1 roll cshow pop pop
|
|
|
634 |
textrenderingprocs TextRenderingMode get exec
|
|
|
635 |
}
|
|
|
636 |
}
|
|
|
637 |
ifelse
|
|
|
638 |
}
|
|
|
639 |
ifelse /Show gput
|
|
|
640 |
} bdef
|
|
|
641 |
/showfirst { setshowstate Show } def
|
|
|
642 |
|
|
|
643 |
/Tj {
|
|
|
644 |
|
|
|
645 |
} bdef
|
|
|
646 |
/' { T* Tj } bdef
|
|
|
647 |
/" { exch Tc exch Tw T* Tj } bdef
|
|
|
648 |
/TJ {
|
|
|
649 |
|
|
|
650 |
dup type /stringtype eq {
|
|
|
651 |
Show
|
|
|
652 |
} { -1000 div
|
|
|
653 |
currentfont /ScaleMatrix .knownget { 0 get mul } if
|
|
|
654 |
|
|
|
655 |
} ifelse
|
|
|
656 |
} forall settextposition
|
|
|
657 |
} bdef
|
|
|
658 |
|
|
|
659 |
/tf { setfillstate currentpoint fill moveto } bdef
|
|
|
660 |
/tn { currentpoint newpath moveto } bdef % Obsolete, never used.
|
|
|
661 |
% For stroking characters, temporarily restore the graphics CTM so that
|
|
|
662 |
% the line width will be transformed properly.
|
|
|
663 |
/Tmatrix matrix def
|
|
|
664 |
/tS
|
|
|
665 |
{ setstrokestate
|
|
|
666 |
currentpoint //Tmatrix currentmatrix TextSaveMatrix setmatrix stroke
|
|
|
667 |
setmatrix moveto
|
|
|
668 |
} bdef
|
|
|
669 |
/tB { gsave tf grestore tS } bdef
|
|
|
670 |
% This does the wrong thing if there have been multiple text operations
|
|
|
671 |
% within a single BT/ET pair, but it's a start.
|
|
|
672 |
/tW { } bdef
|
|
|
673 |
|
|
|
674 |
end readonly put % GS_PDF_ProcSet
|
|
|
675 |
|
|
|
676 |
.setglobal
|