summaryrefslogtreecommitdiff
path: root/gs/lib/pdf_ops.ps
blob: ced83952b3759d152472130c98c2deb46c57627b (plain)
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
%    Copyright (C) 1994, 1996, 1997, 1998 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_ops.ps
% 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
%	Show
%	TextOrigin		% origin of current line, in text space
%	TextSaveMatrix		% matrix at time of BT
% (The following correspond directly to PDF state parameters.)
%	FillColor
%	FillColorSpace
%	StrokeColor
%	StrokeColorSpace
%	TextSpacing
%	TextHScaling
%	Leading
%	TextFont
%	TextMatrix
%	TextRise
%	TextRenderingMode
%	WordSpacing

/nodict 1 dict def
nodict /self { //nodict } executeonly put
nodict readonly pop

/beginpage
 { //nodict 20 dict .copydict begin graphicsbeginpage textbeginpage
 } bdef
/endpage
 { showpage end
 } bdef

/graphicsbeginpage { initgraphics  0 g  0 G } bdef

/gput		% <value> <key> gput -
 { exch currentdict //nodict eq { /self dup load end 5 dict begin def } if
		% If we're in a Level 1 system, we need to grow the
		% dictionary explicitly.
   currentdict length currentdict maxlength ge %eq
    { currentdict dup length 3 mul 2 idiv 1 add dict .copydict end begin 
    }
   if def
 } bdef

/q {
  gsave //nodict begin
} bdef
% Some PDF files have excess Q operators!
/Q {
  currentdict /self .knownget { exec //nodict eq { end grestore } if } if
} bdef

% ---------------- Color setting ---------------- %

/fcput		% <color> <colorspace> fcput -
 { /FillColorSpace gput /FillColor gput
 } bdef
/scput		% <color> <colorspace> scput -
 { /StrokeColorSpace gput /StrokeColor gput
 } bdef

/csdevgray [/DeviceGray] readonly def
/csdevrgb [/DeviceRGB] readonly def
/csdevcmyk [/DeviceCMYK] readonly def
/nullpattern1 mark
   /PatternType 1 /PaintType 1 /TilingType 3 /BBox [0 0 0 0]
   /XStep 1 /YStep 1 /PaintProc { }
.dicttomark readonly def
/nullpattern2 nullpattern1 dup length dict copy readonly def

% Each entry in the color space dictionary is a procedure of the form
%	<cspace> -proc- <cspace> <initial-color>
/CSdict mark
  /DeviceGray { 0 } bind
  /DeviceRGB { [0 0 0] cvx } bind
  /DeviceCMYK { [0 0 0 1] cvx } bind
  /CIEBasedA { 0 } bind
  /CIEBasedABC { [0 0 0] 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 {
      //nullpattern1 matrix makepattern
    } {
      //nullpattern2 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
% We have to break up sc according to the number of operands.
/sc1 { /FillColor gput } bdef
/SC1 { /StrokeColor gput } bdef
/sc* { /FillColor load astore pop } bdef
/SC* { /StrokeColor load astore pop } bdef

% ---------------- Color installation ---------------- %

% Establish a given color (and color space) as current.
/setfillcolor { FillColor FillColorSpace setgcolor } def
/setstrokecolor { StrokeColor StrokeColorSpace setgcolor } def
/Cdict 15 dict dup begin	% <color...> <colorspace> -proc- -
  /DeviceGray { pop setgray } bdef
  /DeviceRGB { pop setrgbcolor } bdef
  /DeviceCMYK { pop setcmykcolor } bdef
  /CIEBasedA
   { dup currentcolorspace eq { pop } { setcolorspace } ifelse setcolor } bdef
  /CIEBasedABC /CIEBasedA load def
  /CIEBasedDEF /CIEBasedA load def
  /CIEBasedDEFG /CIEBasedA load def
  /Separation /CIEBasedA load def
  /DeviceN /CIEBasedA load def
  /Indexed /CIEBasedA load def
  /Pattern
   { dup currentcolorspace eq { pop } { setcolorspace } ifelse
     dup /Matrix get makepattern setcolor
   } bdef
end def
/setgcolor	% (null | <color...>) <colorspace> setgcolor -
 { 1 index null eq
    { pop pop }
    { dup 0 get //Cdict exch get exec }
   ifelse
 } bdef
/fsexec		% <fillop|strokeop> fsexec -
 {		% Preserve the current point, if any.
    { currentpoint } stopped
    { $error /newerror false put   cvx exec }
    { 3 -1 roll cvx exec moveto }
   ifelse
 } bdef

% ---------------- Path painting and clipping ---------------- %

/S { setstrokecolor /stroke fsexec } bdef
/f { setfillcolor /fill fsexec } bdef
/f* { setfillcolor /eofill fsexec } bdef
/n { newpath } bdef		% don't allow n to get bound in
/s { closepath S } bdef
/B { gsave setfillcolor fill grestore S } bdef
/b { closepath B } bdef
/B* { gsave setfillcolor eofill grestore S } bdef
/b* { closepath B* } bdef

% Clipping:

/Wdict 4 dict dup begin
/S { gsave setstrokecolor stroke grestore n } bdef
/f { gsave setfillcolor fill grestore n } bdef
/f* { gsave setfillcolor eofill grestore n } bdef
/n { end clip newpath } bdef
end readonly def
/W { //Wdict begin } bdef
/W*dict 4 dict dup begin
Wdict { def } forall
/n { end eoclip 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
   /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
 } bdef
/settextstate { TextSaveMatrix setmatrix settextmatrix } bdef

/BT
 { currentdict /TextMatrix .knownget
    { identmatrix pop }
    { matrix /TextMatrix gput }
   ifelse
   currentdict /TextOrigin .knownget
    { dup 0 0 put 1 0 put }
    { [0 0] cvx /TextOrigin gput }
   ifelse
    { showfirst } /Show gput
   currentdict /TextSaveMatrix .knownget not
    { matrix dup /TextSaveMatrix gput }
   if currentmatrix pop settextmatrix 0 0 moveto
   TextFont dup null eq { pop } { setfont } ifelse
 } bdef
/ET
 { TextSaveMatrix setmatrix
 } bdef
/Tc { /TextSpacing gput { showfirst } /Show gput } bdef
/TL { /TextLeading gput } bdef
/Tr { /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 ---------------- %

/Tf		% <font> <scale> Tf -
 { dup 1 eq { pop } { scalefont } ifelse
   dup setfont /TextFont gput
 } bdef

% Read a CFF font.
/FRD		% <resdict> <file> FRD -
 { /FontSetInit /ProcSet findresource begin ReadData
 } 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.
/.updatefont		% <font> <Encoding|null> <Metrics|null> .updatefont
			%   <font'> <copied>
 { 2 index 4 1 roll
   dup null ne
    { 3 -1 roll true .copyfontdict dup /Metrics 4 -1 roll put exch }
    { pop }
   ifelse
   dup null ne 1 index 3 index /Encoding get ne and
    { exch false .copyfontdict dup /Encoding 4 -1 roll put }
    { pop }
   ifelse exch 1 index ne
 } bdef

% ---------------- Text positioning ---------------- %

/Td
 { TextOrigin exch 4 -1 roll add 3 1 roll add
   2 copy /TextOrigin load astore pop moveto
 } bdef
/TD { dup neg /TextLeading gput Td } bdef
/T* { 0 TextLeading neg Td } bdef
/Tm
 { TextMatrix astore pop settextstate
   0 0 /TextOrigin load astore pop
   0 0 moveto
 } bdef

% ---------------- Text painting ---------------- %

/textrenderingprocs [		% (0 is handled specially)
   { tf } { tS } { tB } { tn }
	% We don't know what the clipping modes mean....
   4 copy
] readonly def
/setshowstate
 { WordSpacing 0 eq TextSpacing 0 eq and
    { TextRenderingMode 0 eq
       { { setfillcolor show } }
       { { false charpath textrenderingprocs TextRenderingMode get exec } }
      ifelse
    }
    { TextRenderingMode 0 eq
       { WordSpacing 0 eq
          { { setfillcolor TextSpacing exch 0 exch ashow } }
	  { TextSpacing 0 eq
	     { { setfillcolor WordSpacing exch 0 exch 32 exch widthshow } }
	     { { setfillcolor WordSpacing exch TextSpacing exch 0 32 4 2 roll 0 exch awidthshow } }
	    ifelse
	  }
	 ifelse
       }
       { { 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 xword xchar
	    { pop pop (x) dup 0 3 index put false charpath
			% Stack: xword xchar ccode
	      3 copy 32 eq { add } { exch pop } ifelse 0 rmoveto pop
	    }
	   4 -1 roll cshow pop pop
	   textrenderingprocs TextRenderingMode get exec
	 }
       }
      ifelse
    }
   ifelse /Show gput
 } bdef
/showfirst { setshowstate Show } def

/Tj { Show } bdef
/' { T* Show } bdef
/" { exch Tc exch Tw T* Show } bdef
/TJ
 {  { dup type /stringtype eq
       { Show
       }
       { -1000 div
	 currentfont /ScaleMatrix .knownget { 0 get mul } if
	 0 rmoveto
       }
      ifelse
    }
   forall
 } bdef

/tf { setfillcolor currentpoint fill moveto } bdef
/tn { currentpoint newpath moveto } bdef
% For stroking characters, temporarily restore the graphics CTM so that
% the line width will be transformed properly.
/Tmatrix matrix def
/tS
 { setstrokecolor
   currentpoint //Tmatrix currentmatrix TextSaveMatrix setmatrix stroke
   setmatrix moveto
 } bdef
/tB { gsave tf grestore tS } bdef

end readonly put		% GS_PDF_ProcSet

.setglobal