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_main.ps,v 1.100 2005/09/23 18:21:23 ray Exp $
|
|
|
17 |
% pdf_main.ps
|
|
|
18 |
% PDF file- and page-level operations.
|
|
|
19 |
|
|
|
20 |
/.setlanguagelevel where { pop 2 .setlanguagelevel } if
|
|
|
21 |
.currentglobal true .setglobal
|
|
|
22 |
/pdfdict where { pop } { /pdfdict 100 dict def } ifelse
|
|
|
23 |
pdfdict begin
|
|
|
24 |
|
|
|
25 |
% Patch in an obsolete variable used by some third-party software.
|
|
|
26 |
/#? false def
|
|
|
27 |
|
|
|
28 |
% Test whether the current output device handles pdfmark.
|
|
|
29 |
/.writepdfmarkdict 1 dict dup /pdfmark null put readonly def
|
|
|
30 |
/.writepdfmarks { % - .writepdfmarks <bool>
|
|
|
31 |
currentdevice //.writepdfmarkdict .getdeviceparams
|
|
|
32 |
mark eq { false } { pop pop true } ifelse
|
|
|
33 |
systemdict /DOPDFMARKS known or
|
|
|
34 |
} bind def
|
|
|
35 |
|
|
|
36 |
% For simplicity, we use a single interpretation dictionary for all
|
|
|
37 |
% PDF graphics execution, even though this is too liberal.
|
|
|
38 |
/pdfopdict mark
|
|
|
39 |
objopdict { } forall
|
|
|
40 |
drawopdict { } forall
|
|
|
41 |
/endstream { exit } bind
|
|
|
42 |
(%%EOF) cvn { exit } bind % for filters
|
|
|
43 |
% PDF 1.1 operators
|
|
|
44 |
/BX { /BXlevel BXlevel 1 add store } bind
|
|
|
45 |
/EX { /BXlevel BXlevel 1 sub store } bind
|
|
|
46 |
/PS { cvx exec } bind
|
|
|
47 |
% PDF 1.2 operators
|
|
|
48 |
/BMC { pop } bind
|
|
|
49 |
/BDC { pop pop } bind
|
|
|
50 |
/EMC { }
|
|
|
51 |
/MP { pop } bind
|
|
|
52 |
/DP { pop pop } bind
|
|
|
53 |
.dicttomark readonly def
|
|
|
54 |
|
|
|
55 |
% ======================== Main program ======================== %
|
|
|
56 |
|
|
|
57 |
end % pdfdict
|
|
|
58 |
userdict begin
|
|
|
59 |
|
|
|
60 |
/defaultfontname /Times-Roman def
|
|
|
61 |
|
|
|
62 |
% Make sure the registered encodings are loaded, so we don't run the risk
|
|
|
63 |
% that some of the indices for their names will overflow the packed
|
|
|
64 |
% representation. (Yes, this is a hack.)
|
|
|
65 |
SymbolEncoding pop
|
|
|
66 |
DingbatsEncoding pop
|
|
|
67 |
|
|
|
68 |
% Redefine 'run' so it recognizes PDF files.
|
|
|
69 |
systemdict begin
|
|
|
70 |
/.runps /run load def
|
|
|
71 |
/run {
|
|
|
72 |
dup type /filetype ne { (r) file } if
|
|
|
73 |
% skip leading whitespace characters (actually anything less than or equal to <sp>)
|
|
|
74 |
{ dup ( ) .peekstring not { false exit } if
|
|
|
75 |
dup 0 get 32 le { pop dup read pop pop } { true exit } ifelse
|
|
|
76 |
} loop
|
|
|
77 |
{
|
|
|
78 |
(%) eq {
|
|
|
79 |
dup ( ) .peekstring {
|
|
|
80 |
(%PDF-) eq {
|
|
|
81 |
dup (%stdin) (r) file eq {
|
|
|
82 |
% Copy PDF from stdin to temporary file then run it.
|
|
|
83 |
null (w+) //systemdict /.tempfile get exec exch 3 1 roll
|
|
|
84 |
% stack: tempname stdin tempfile
|
|
|
85 |
64000 string
|
|
|
86 |
{
|
|
|
87 |
% stack: tempname stdin tempfile string
|
|
|
88 |
2 index 1 index readstring
|
|
|
89 |
exch 3 index exch writestring
|
|
|
90 |
not { exit } if
|
|
|
91 |
}
|
|
|
92 |
loop
|
|
|
93 |
pop exch closefile
|
|
|
94 |
% stack: tempname tempfile
|
|
|
95 |
dup 0 setfileposition
|
|
|
96 |
dup runpdf
|
|
|
97 |
closefile deletefile
|
|
|
98 |
} {
|
|
|
99 |
runpdf
|
|
|
100 |
} ifelse
|
|
|
101 |
} {
|
|
|
102 |
cvx .runps % doesn't start with %PDF-
|
|
|
103 |
} ifelse
|
|
|
104 |
} {
|
|
|
105 |
pop cvx .runps % didn't read 5 characters
|
|
|
106 |
} ifelse
|
|
|
107 |
} {
|
|
|
108 |
cvx .runps % didn't start with %
|
|
|
109 |
} ifelse
|
|
|
110 |
} {
|
|
|
111 |
pop closefile % file was empty
|
|
|
112 |
} ifelse
|
|
|
113 |
} bind odef
|
|
|
114 |
currentdict /runpdfstring .undef
|
|
|
115 |
|
|
|
116 |
|
|
|
117 |
/runpdfbegin { % <file> runpdf -
|
|
|
118 |
userdict begin
|
|
|
119 |
% It turns out that the PDF interpreter uses memory more
|
|
|
120 |
% effectively if it is run under at least one level of save.
|
|
|
121 |
% This is counter-intuitive, and we don't understand why it happens,
|
|
|
122 |
% but the improvement is significant.
|
|
|
123 |
/PDFTopSave save def
|
|
|
124 |
|
|
|
125 |
/Page# null def
|
|
|
126 |
/Page null def
|
|
|
127 |
/DSCPageCount 0 def
|
|
|
128 |
/PDFSave null def
|
|
|
129 |
GS_PDF_ProcSet begin
|
|
|
130 |
pdfdict begin
|
|
|
131 |
pdfopen begin
|
|
|
132 |
Trailer /Root oget /Pages oget /CropBox knownoget
|
|
|
133 |
{ oforce_array normrect mark /CropBox 3 -1 roll /PAGES pdfmark
|
|
|
134 |
}
|
|
|
135 |
if
|
|
|
136 |
/FirstPage where
|
|
|
137 |
{ pop FirstPage dup pdfpagecount gt
|
|
|
138 |
{ (\nRequested FirstPage is greater than the number of pages in the file: ) print
|
|
|
139 |
pdfpagecount = flush
|
|
|
140 |
} if
|
|
|
141 |
} {
|
|
|
142 |
1
|
|
|
143 |
} ifelse
|
|
|
144 |
/LastPage where { pop LastPage pdfpagecount .min } { pdfpagecount } ifelse
|
|
|
145 |
1 index 1 index gt
|
|
|
146 |
{ ( No pages will be processed \(FirstPage > LastPage\).) = flush }
|
|
|
147 |
{ QUIET not
|
|
|
148 |
{ (Processing pages ) print 1 index =only ( through ) print dup =only
|
|
|
149 |
(.) = flush
|
|
|
150 |
}
|
|
|
151 |
if
|
|
|
152 |
}
|
|
|
153 |
ifelse
|
|
|
154 |
} bind def
|
|
|
155 |
|
|
|
156 |
/dopdfpages { % firstpage# lastpage# dopdfpages -
|
|
|
157 |
<< /PDFScanRules true >> setuserparams % set scanning rules for PDF vs. PS
|
|
|
158 |
1 exch
|
|
|
159 |
{ dup /Page# exch store
|
|
|
160 |
QUIET not { (Page ) print dup == flush } if
|
|
|
161 |
pdfgetpage pdfshowpage
|
|
|
162 |
} for
|
|
|
163 |
<< /PDFScanRules null >> setuserparams % restore scanning rules for PS
|
|
|
164 |
} bind def
|
|
|
165 |
|
|
|
166 |
/runpdfend {
|
|
|
167 |
Repaired { printrepaired } if
|
|
|
168 |
currentdict pdfclose
|
|
|
169 |
end % temporary dict
|
|
|
170 |
end % pdfdict
|
|
|
171 |
end % GS_PDF_ProcSet
|
|
|
172 |
PDFTopSave restore
|
|
|
173 |
end % userdict
|
|
|
174 |
} bind def
|
|
|
175 |
|
|
|
176 |
/runpdf { % <file> runpdf -
|
|
|
177 |
runpdfbegin
|
|
|
178 |
dopdfpages
|
|
|
179 |
runpdfend
|
|
|
180 |
} bind def
|
|
|
181 |
|
|
|
182 |
end % systemdict
|
|
|
183 |
% Redefine the procedure that the C code uses for running piped input.
|
|
|
184 |
% It is OK to use { (%stdin) run } here, because a startjob cannot occur.
|
|
|
185 |
/.runstdin {
|
|
|
186 |
{ (%stdin) run } execute0
|
|
|
187 |
} bind def
|
|
|
188 |
|
|
|
189 |
end % userdict
|
|
|
190 |
pdfdict begin
|
|
|
191 |
|
|
|
192 |
% ======================== File parsing ======================== %
|
|
|
193 |
|
|
|
194 |
% Read the cross-reference and trailer sections.
|
|
|
195 |
|
|
|
196 |
/traileropdict mark
|
|
|
197 |
(<<) cvn { mark } bind
|
|
|
198 |
(>>) cvn { { .dicttomark } stopped {
|
|
|
199 |
( **** File has unbalanced >> in trailer.\n) pdfformaterror
|
|
|
200 |
} if } bind
|
|
|
201 |
([) cvn { mark } bind % ditto
|
|
|
202 |
(]) cvn dup load
|
|
|
203 |
% /true true % see .pdfexectoken in pdf_base.ps
|
|
|
204 |
% /false false % ibid.
|
|
|
205 |
% /null null % ibid.
|
|
|
206 |
/R { /resolveR cvx 3 packedarray cvx } bind % see Objects below
|
|
|
207 |
/startxref /exit load
|
|
|
208 |
.dicttomark readonly def
|
|
|
209 |
|
|
|
210 |
% Because of EOL conversion, lines with fixed contents might be followed
|
|
|
211 |
% by one or more blanks.
|
|
|
212 |
/lineeq % <filestr> <conststr> lineeq <bool>
|
|
|
213 |
{ anchorsearch
|
|
|
214 |
{ pop { ( ) anchorsearch not { () eq exit } if pop } loop }
|
|
|
215 |
{ pop false }
|
|
|
216 |
ifelse
|
|
|
217 |
} bind def
|
|
|
218 |
/linene { lineeq not } bind def
|
|
|
219 |
|
|
|
220 |
% Read original version (pre PDF 1.5) of the xref table.
|
|
|
221 |
% Note: The position is the location of 'xref'. The current PDFfile
|
|
|
222 |
% position is just after the 'XREF'.
|
|
|
223 |
/readorigxref % <pos> readorigxref <trailerdict>
|
|
|
224 |
{
|
|
|
225 |
pop % We do not need the position.
|
|
|
226 |
|
|
|
227 |
{ PDFfile token pop % first object # or trailer
|
|
|
228 |
dup /trailer eq { pop exit } if
|
|
|
229 |
PDFfile pdfstring readline pop
|
|
|
230 |
token pop % entry count
|
|
|
231 |
% remaining must be whitespace only (otherwise this xref Size was invalid.
|
|
|
232 |
exch dup length 0 ne {
|
|
|
233 |
false 1 index { 32 gt { pop true exit } if } forall {
|
|
|
234 |
( **** Warning: xref subsection header has extra characters.\n)
|
|
|
235 |
pdfformaterror
|
|
|
236 |
/setxrefentry cvx /syntaxerror signalerror
|
|
|
237 |
} if
|
|
|
238 |
} if
|
|
|
239 |
pop % remove last
|
|
|
240 |
% This section might be adding new objects:
|
|
|
241 |
% ensure that Objects and Generations are big enough.
|
|
|
242 |
% stack: <err count> <first obj> <entry count>
|
|
|
243 |
2 copy add growPDFobjects
|
|
|
244 |
{ % stack: <err count> <obj num>
|
|
|
245 |
% Read xref line
|
|
|
246 |
PDFfile 20 string readstring pop % always read 20 chars.
|
|
|
247 |
token pop % object position
|
|
|
248 |
exch token pop % generation #
|
|
|
249 |
exch token pop % n or f
|
|
|
250 |
exch % stack: <err count> <obj#> <loc> <gen#> <tag> <remainder of line>
|
|
|
251 |
dup length 0 ne {
|
|
|
252 |
% check to make sure trailing garbage is just white space
|
|
|
253 |
dup { 32 gt { 5 -1 roll 1 add 5 1 roll } if } forall % bump error count on garbage
|
|
|
254 |
} if
|
|
|
255 |
pop % Stack: <err count> <obj#> <loc> <gen#> <tag>
|
|
|
256 |
dup /n eq { % xref line tag is /n
|
|
|
257 |
pop % pop dup of line tag
|
|
|
258 |
Objects 3 index lget null eq { % later update might have set it
|
|
|
259 |
|
|
|
260 |
setxrefentry % Save xref entry
|
|
|
261 |
3 -1 roll pop % Remove ObjectStream object onumber
|
|
|
262 |
} if
|
|
|
263 |
}
|
|
|
264 |
{ % xref line tag was not /n
|
|
|
265 |
/f ne % verify that the tag was /f
|
|
|
266 |
{ /setxrefentry cvx /syntaxerror signalerror
|
|
|
267 |
} if
|
|
|
268 |
} ifelse
|
|
|
269 |
pop pop % pop <obj location> and <gen num>
|
|
|
270 |
% stack: <err count> <obj num>
|
|
|
271 |
1 add % increment object number
|
|
|
272 |
} repeat
|
|
|
273 |
pop % pop <obj #>
|
|
|
274 |
} loop
|
|
|
275 |
|
|
|
276 |
( **** Warning: length of some xref entries is not equal to 20 bytes.\n)
|
|
|
277 |
pdfformaterror
|
|
|
278 |
} if
|
|
|
279 |
PDFfile traileropdict .pdfrun
|
|
|
280 |
} bind def
|
|
|
281 |
|
|
|
282 |
% This dicitonary is used to read the xref dictionary. It should work for
|
|
|
283 |
% reading any dictionary. dictlevelcount must contain 0.
|
|
|
284 |
/xrefopdict mark
|
|
|
285 |
(<<) cvn { /dictlevelcount dictlevelcount 1 add def mark } bind
|
|
|
286 |
(>>) cvn { .dicttomark /dictlevelcount dictlevelcount 1 sub def
|
|
|
287 |
dictlevelcount 0 eq { exit} if } bind
|
|
|
288 |
([) cvn { mark } bind % ditto
|
|
|
289 |
(]) cvn dup load
|
|
|
290 |
% /true true % see .pdfexectoken in pdf_base.ps
|
|
|
291 |
% /false false % ibid.
|
|
|
292 |
% /null null % ibid.
|
|
|
293 |
/R { /resolveR cvx 3 packedarray cvx } bind % see Objects below
|
|
|
294 |
.dicttomark readonly def
|
|
|
295 |
|
|
|
296 |
% Get a variable length positive integer value from a stream. A value
|
|
|
297 |
% of zero is returned if the count is zero.
|
|
|
298 |
/getintn { % <stream> <count> getintn int
|
|
|
299 |
|
|
|
300 |
exch pop % Discard stream
|
|
|
301 |
} bind def
|
|
|
302 |
|
|
|
303 |
% This array contains handlers for processing the different types of
|
|
|
304 |
% entries in the XRef stream.
|
|
|
305 |
% Stack: <Xrefdict> <xref stream> <Index array> <pair loc> <obj num>
|
|
|
306 |
% <field 2> <field 3>
|
|
|
307 |
% The handlers leave the stack unchanged.
|
|
|
308 |
/xref15entryhandlers [
|
|
|
309 |
{ % XRef entry type 0 - free or f type xref entry
|
|
|
310 |
% (free ) print
|
|
|
311 |
% (obj num: ) print 2 index pdfstring cvs print ( ) print
|
|
|
312 |
% (loc: ) print 1 index pdfstring cvs print ( ) print
|
|
|
313 |
% (gen: ) print dup === flush
|
|
|
314 |
} bind % Do nothing for free xref entries
|
|
|
315 |
% XRef entry type 1 - normal or n type xref entry
|
|
|
316 |
{ % field 2 = obj loc, field 3 = gen num
|
|
|
317 |
% (normal ) print
|
|
|
318 |
% (obj num: ) print 2 index pdfstring cvs print ( ) print
|
|
|
319 |
% (loc: ) print 1 index pdfstring cvs print ( ) print
|
|
|
320 |
% (gen: ) print dup === flush
|
|
|
321 |
|
|
|
322 |
setxrefentry
|
|
|
323 |
3 -1 roll pop % remove stream number
|
|
|
324 |
} bind
|
|
|
325 |
% XRef entry type 2 - compressed object type xref entry
|
|
|
326 |
{ % field 2 = object stream num, field 3 = index into object stream
|
|
|
327 |
% (Compressed objects: ) print
|
|
|
328 |
% (obj num: ) print 2 index pdfstring cvs print ( ) print
|
|
|
329 |
% (field 2: ) print 1 index pdfstring cvs print ( ) print
|
|
|
330 |
% (field 3: ) print dup === flush
|
|
|
331 |
|
|
|
332 |
} bind
|
|
|
333 |
] def
|
|
|
334 |
|
|
|
335 |
% Read the PDF 1.5 version of the xref table.
|
|
|
336 |
% Note: The position is the location of the start of the dictionary object
|
|
|
337 |
% In PDF 1.5, the XRef dictionary also serves as the trailer dictionary
|
|
|
338 |
/readpdf15xref % <pos> readpdf15xref <trailerdict>
|
|
|
339 |
{
|
|
|
340 |
PDFfile exch setfileposition % move to start of object
|
|
|
341 |
% Get object number, revision, and 'obj' and discard
|
|
|
342 |
PDFfile token pop pop
|
|
|
343 |
PDFfile token pop pop
|
|
|
344 |
PDFfile token pop pop
|
|
|
345 |
% Get the XRef dicitionary
|
|
|
346 |
/dictlevelcount 0 def PDFfile xrefopdict .pdfrun
|
|
|
347 |
% Verify that we have an XRef dictionary
|
|
|
348 |
dup /Type get /XRef ne {
|
|
|
349 |
/readpdf15xref cvx /syntaxerror signalerror
|
|
|
350 |
} if
|
|
|
351 |
% Ensure that we we have room in the objects array, etc.
|
|
|
352 |
dup /Size get growPDFobjects
|
|
|
353 |
% Create a stream for the XRef data
|
|
|
354 |
PDFfile token pop pop % Skip over 'stream'
|
|
|
355 |
dup stream false resolvestream
|
|
|
356 |
% Stack: <XRefdict> <xref stream>
|
|
|
357 |
% The Index array defines the ranges of object numbers in the
|
|
|
358 |
% XRef stream. Each value pair is consists of starting object
|
|
|
359 |
% number and the count of consecutive objects.
|
|
|
360 |
% Get the Index array, if present
|
|
|
361 |
1 index /Index .knownget not { % If no Index array ...
|
|
|
362 |
[ 0 3 index /Size get ] % Default = [ 0 Size ]
|
|
|
363 |
} if
|
|
|
364 |
% Loop through the Index array
|
|
|
365 |
|
|
|
366 |
% Get start and end of object range
|
|
|
367 |
2 copy get % Start of the range
|
|
|
368 |
dup 3 index 3 index 1 add get % Number of entries in range
|
|
|
369 |
% Loop through the range of object numbers
|
|
|
370 |
add 1 sub 1 exch { % Form end of range, set increment = 1
|
|
|
371 |
% Stack: <Xrefdict> <xref stream> <Index array> <pair loc> <obj num>
|
|
|
372 |
% Get xref parameters. Note: The number of bytes for each parameter
|
|
|
373 |
% is defined by the entries in the W array.
|
|
|
374 |
4 index /W get aload pop % Get W array values
|
|
|
375 |
% The first field indicates type of entry. Get first field value.
|
|
|
376 |
% If the num. of bytes for field 1 is 0 then default field value is 1
|
|
|
377 |
3 -1 roll dup 0 eq { pop 1 } { 6 index exch getintn } ifelse
|
|
|
378 |
% Get the handler for the xref entry type. We will execute the
|
|
|
379 |
% handler after we get the other two field values.
|
|
|
380 |
xref15entryhandlers exch get
|
|
|
381 |
3 -1 roll 6 index exch getintn % Get second field
|
|
|
382 |
3 -1 roll 6 index exch getintn % Get third field
|
|
|
383 |
3 -1 roll exec % Execute Xref entry handler
|
|
|
384 |
pop pop pop % Remove field values and obj num
|
|
|
385 |
} for % Loop through Xref entries
|
|
|
386 |
pop % Remove Index array pair loc
|
|
|
387 |
} for % Loop through Index array entries
|
|
|
388 |
pop pop % Remove Index array and xref stream
|
|
|
389 |
} bind def
|
|
|
390 |
|
|
|
391 |
% Read the cross-reference table.
|
|
|
392 |
% <pos> is the position either from the startxref statement or the /Prev
|
|
|
393 |
% entry in the prior trailer dictionary.
|
|
|
394 |
/readxref % <pos> readxref <trailerdict>
|
|
|
395 |
{
|
|
|
396 |
PDFoffset add PDFfile exch setfileposition
|
|
|
397 |
% In some PDF files, this position actually points to
|
|
|
398 |
% white space before the xref line. Skip over this here.
|
|
|
399 |
{
|
|
|
400 |
PDFfile fileposition PDFfile read pop 32 gt { exit } if pop
|
|
|
401 |
} loop
|
|
|
402 |
dup % Make copy of the file position (before last char was read).
|
|
|
403 |
PDFfile exch setfileposition
|
|
|
404 |
% The PDF specification says that the 'xref' must be on a line
|
|
|
405 |
% by itself. The code here formerly used readline and linene to
|
|
|
406 |
% check this. However, Acrobat Reader only requires the line to
|
|
|
407 |
% begin with 'xref', and there are enough applications producing
|
|
|
408 |
% non-compliant PDF files that we have to do this too.
|
|
|
409 |
PDFfile pdfstring 0 4 getinterval readstring pop
|
|
|
410 |
(xref) eq
|
|
|
411 |
{ readorigxref } % 'xref' -> original xref table
|
|
|
412 |
{ readpdf15xref } % otherwise assume PDF 1.5 xref stream
|
|
|
413 |
ifelse
|
|
|
414 |
} bind def
|
|
|
415 |
|
|
|
416 |
% Open a PDF file and read the header, trailer, and cross-reference.
|
|
|
417 |
/pdfopen { % <file> pdfopen <dict>
|
|
|
418 |
% Color space substitution in PDF is handled somewhat differently
|
|
|
419 |
% than in PostScript. A given device color space will be substituted
|
|
|
420 |
% if the corresponding "Default..." entry exists in the Page's
|
|
|
421 |
% Resource dictionary (which might be inhereted); there is no
|
|
|
422 |
% UseCIEColor to enable/disable color mapping.
|
|
|
423 |
%
|
|
|
424 |
% This behavior is achieved by always setting UseCIEColor to true
|
|
|
425 |
% in the page device dictionary. If the value of this parameter was
|
|
|
426 |
% originally false (i.e.: the output device does not perform color
|
|
|
427 |
% space substitution by default), the instances DefaultGray,
|
|
|
428 |
% DefaultRGB, and DefaultCMYK of the (local) ColorSpace category
|
|
|
429 |
% are redefined to be DeviceGray, DeviceRGB, and DeviceCMYK,
|
|
|
430 |
% respectively. This is not done if UseCIEColor is true by default,
|
|
|
431 |
% as in that case color substitution is presumably desired even
|
|
|
432 |
% if the file does not request it.
|
|
|
433 |
currentpagedevice /UseCIEColor .knownget dup { pop } if not
|
|
|
434 |
{ .currentglobal false .setglobal
|
|
|
435 |
/DefaultGray { /DeviceGray } cvlit /ColorSpace defineresource pop
|
|
|
436 |
/DefaultRGB { /DeviceRGB } cvlit /ColorSpace defineresource pop
|
|
|
437 |
/DefaultCMYK { /DeviceCMYK } cvlit /ColorSpace defineresource pop
|
|
|
438 |
.setglobal
|
|
|
439 |
}
|
|
|
440 |
if
|
|
|
441 |
pdfopenfile begin
|
|
|
442 |
pdfopencache
|
|
|
443 |
.writepdfmarks {
|
|
|
444 |
% Copy bookmarks (outline) to the output.
|
|
|
445 |
Trailer /Root oget /Outlines knownoget {
|
|
|
446 |
/First knownoget {
|
|
|
447 |
{ dup writeoutline /Next knownoget not { exit } if } loop
|
|
|
448 |
} if
|
|
|
449 |
} if
|
|
|
450 |
} if % end .writepdfmarks
|
|
|
451 |
currentdict end
|
|
|
452 |
} bind def
|
|
|
453 |
|
|
|
454 |
% Verify that each entry in the xref table is pointing at an object with
|
|
|
455 |
% the correct object number and generation number.
|
|
|
456 |
/verify_xref % - verify_xref -
|
|
|
457 |
{ 1 1 Objects llength 1 sub % stack: 1 1 <number of objects - 1>
|
|
|
458 |
{ % Check if the object is free (i.e. not used). The values in
|
|
|
459 |
% Generations is the generation number plus 1. If the value in
|
|
|
460 |
% Generations is zero then the object is free.
|
|
|
461 |
Generations 1 index lget % Get the genration number
|
|
|
462 |
|
|
|
463 |
ObjectStream 1 index lget % Check if object is in objectstream
|
|
|
464 |
|
|
|
465 |
{ % Use stop context since we may get an error if object is invalid
|
|
|
466 |
dup Objects exch lget % Get the object location
|
|
|
467 |
PDFoffset add PDFfile exch setfileposition
|
|
|
468 |
true % Stack: <obj num> <true>
|
|
|
469 |
PDFfile token pop % Read object number from file
|
|
|
470 |
2 index eq { % Verify object number
|
|
|
471 |
PDFfile token pop % Read generation number from file
|
|
|
472 |
Generations 3 index % Get specified generaton number
|
|
|
473 |
lget 1 sub % Gen numbs are stored with 1 added.
|
|
|
474 |
eq { % Verify generation number
|
|
|
475 |
PDFfile token pop /obj eq { % Verify 'obj' text
|
|
|
476 |
pop false % We have valid object, do not rebuild
|
|
|
477 |
} if
|
|
|
478 |
} if
|
|
|
479 |
} if
|
|
|
480 |
} .internalstopped
|
|
|
481 |
{ true } if % If we stop then we need to rebuild
|
|
|
482 |
{
|
|
|
483 |
( **** Warning: File has an invalid xref entry: )
|
|
|
484 |
pdfformaterror
|
|
|
485 |
pdfstring cvs pdfformaterror
|
|
|
486 |
(. Rebuilding xref table.\n) pdfformaterror
|
|
|
487 |
search_objects
|
|
|
488 |
exit
|
|
|
489 |
} if % If the entry is invalid
|
|
|
490 |
} if % If not in an object stream
|
|
|
491 |
} if % If object entry is not free
|
|
|
492 |
pop % Remove object number
|
|
|
493 |
} for
|
|
|
494 |
} bind odef
|
|
|
495 |
|
|
|
496 |
/pdfopencache { % - pdfopencache -
|
|
|
497 |
% Create and initialize some caches.
|
|
|
498 |
/PageCount pdfpagecount def
|
|
|
499 |
/PageNumbers PageCount 65534 .min dict def
|
|
|
500 |
/PageIndex PageCount 65534 .min array def
|
|
|
501 |
} bind def
|
|
|
502 |
|
|
|
503 |
/pdfopenfile { % <file> pdfopenfile <dict>
|
|
|
504 |
pdfdict readonly pop % can't do it any earlier than this
|
|
|
505 |
15 dict begin
|
|
|
506 |
/LocalResources 0 dict def
|
|
|
507 |
/DefaultQstate //null def % establish binding
|
|
|
508 |
/Printed where { pop } {
|
|
|
509 |
% Guess whether the output device is a printer.
|
|
|
510 |
/Printed currentpagedevice /OutputFile known def
|
|
|
511 |
} ifelse
|
|
|
512 |
/PSLevel1 where { pop } { /PSLevel1 false def } ifelse
|
|
|
513 |
% NB: PDFfile is used outside of the PDF code to determine that a
|
|
|
514 |
% PDF job is being processed; to not change or hide this key.
|
|
|
515 |
cvlit /PDFfile exch def
|
|
|
516 |
/PDFsource PDFfile def
|
|
|
517 |
/Repaired false def
|
|
|
518 |
currentglobal true .setglobal globaldict begin
|
|
|
519 |
/TTFWarnList 0 dict def /UndefProcList 0 dict def
|
|
|
520 |
end .setglobal
|
|
|
521 |
PDFfile dup 0 setfileposition pdfstring readstring
|
|
|
522 |
not {/pdfopen cvx /syntaxerror signalerror} if
|
|
|
523 |
(%PDF-) search not {/pdfopen cvx /syntaxerror signalerror} if
|
|
|
524 |
length /PDFoffset exch def pop
|
|
|
525 |
% some badly formed PDF's (Visioneer) have something other than EOL
|
|
|
526 |
% after the version number. If we get an error, shorten the string
|
|
|
527 |
% and try again.
|
|
|
528 |
false exch % error encountered
|
|
|
529 |
{ { cvr } stopped
|
|
|
530 |
{ exch pop true exch 0 1 index length 1 sub dup 0 eq
|
|
|
531 |
{ pop 0 exit } if % exit if string now empty
|
|
|
532 |
getinterval % trim character from right end and retry
|
|
|
533 |
}
|
|
|
534 |
{ exch {
|
|
|
535 |
( **** Warning: PDF version number not followed by EOL.\n)
|
|
|
536 |
pdfformaterror
|
|
|
537 |
}
|
|
|
538 |
if exit
|
|
|
539 |
}
|
|
|
540 |
ifelse
|
|
|
541 |
} loop
|
|
|
542 |
|
|
|
543 |
/PDFversion exch def
|
|
|
544 |
% Read the last cross-reference table.
|
|
|
545 |
count /pdfemptycount exch def
|
|
|
546 |
/Trailer << >> def % Initialize to an emptry dict.
|
|
|
547 |
{ initPDFobjects findxref readxref } .internalstopped {
|
|
|
548 |
recover_xref_data % Read failed. Attempt to recover xref data.
|
|
|
549 |
search_trailer % Search for the primary trailer
|
|
|
550 |
} {
|
|
|
551 |
/Trailer exch def % Save trailer dict after first xref table
|
|
|
552 |
% Read any previous cross-reference tables. When we are done,
|
|
|
553 |
% verify that the entries in the xref tables are valid if NoVerifyXref
|
|
|
554 |
% is not defined.
|
|
|
555 |
Trailer
|
|
|
556 |
{ /Prev knownoget not { % If no previous xref table then ...
|
|
|
557 |
/NoVerifyXref where { pop } { verify_xref } ifelse exit
|
|
|
558 |
} if
|
|
|
559 |
{ readxref } .internalstopped {
|
|
|
560 |
recover_xref_data % Read failed. Attempt to recover xref data.
|
|
|
561 |
exit % Exit loop since recover gets all obj data.
|
|
|
562 |
} if % If readxref stopped
|
|
|
563 |
% The PDF spec. says that each trailer dict should contain the required
|
|
|
564 |
% entries. However we have seen a PDF file that only has a Prev entry in
|
|
|
565 |
% the initial trailer dict. Acrobat complains but it accepts these files.
|
|
|
566 |
% To work with these files, we are copying any entries which we find in
|
|
|
567 |
% a previous trailer dict which are not present in the initial dict.
|
|
|
568 |
dup {
|
|
|
569 |
Trailer 2 index known {
|
|
|
570 |
pop pop % discard if key already present
|
|
|
571 |
} {
|
|
|
572 |
Trailer 3 1 roll put % add key if not present
|
|
|
573 |
} ifelse
|
|
|
574 |
} forall
|
|
|
575 |
} loop % Loop to previous trailer
|
|
|
576 |
} ifelse % Ifelse readxref stopped
|
|
|
577 |
Trailer /Encrypt knownoget {
|
|
|
578 |
pop
|
|
|
579 |
pdf_process_Encrypt % signal error
|
|
|
580 |
} if
|
|
|
581 |
currentdict end
|
|
|
582 |
} bind def
|
|
|
583 |
|
|
|
584 |
% Look for [\r\n]%%EO from the current position of the file.
|
|
|
585 |
% Return the position of %%EO if found or -1 .
|
|
|
586 |
/findeof { % <file> find_eof <file> <position>
|
|
|
587 |
-1 exch
|
|
|
588 |
{
|
|
|
589 |
dup bytesavailable 4 lt { exit } if
|
|
|
590 |
dup 0 (%%EO) /SubFileDecode filter flushfile
|
|
|
591 |
dup dup fileposition 5 sub setfileposition
|
|
|
592 |
dup 5 string readstring not { pop exit } if
|
|
|
593 |
dup (\r%%EO) eq exch (\n%%EO) eq or {
|
|
|
594 |
dup fileposition 4 sub
|
|
|
595 |
3 1 roll exch pop
|
|
|
596 |
} if
|
|
|
597 |
} loop
|
|
|
598 |
exch
|
|
|
599 |
} bind def
|
|
|
600 |
|
|
|
601 |
% Skip backward over the %%EOF at the end of the PDF file, and read
|
|
|
602 |
% the preceding startxref line. The PDF specification unambiguously
|
|
|
603 |
% requires that the %%EOF appear on a line by itself, and that the
|
|
|
604 |
% startxref and the following position value appear on separate lines;
|
|
|
605 |
% however, some applications truncate the %%EOF to %%EO, and/or put the
|
|
|
606 |
% startxref and the following value on the same line.
|
|
|
607 |
% There seems to be no limit on the amount of garbage that can be
|
|
|
608 |
% appended to the PDF file. Current record (60K) belongs to
|
|
|
609 |
% PDF-Out (v 2.0 - 35). We start the search for %%EO from the last 1024
|
|
|
610 |
% bytes and continue from the beginning of the file.
|
|
|
611 |
/findxref { % - findxref <xrefpos>
|
|
|
612 |
PDFfile dup dup dup 0 setfileposition bytesavailable
|
|
|
613 |
dup /PDFfilelen exch def
|
|
|
614 |
% Find the last %%EOF string (within 1024 bytes)
|
|
|
615 |
1024 sub PDFoffset .max
|
|
|
616 |
setfileposition findeof % search the last 1024 bytes
|
|
|
617 |
dup 0 le {
|
|
|
618 |
pop
|
|
|
619 |
dup PDFoffset setfileposition findeof % search from the beginnibg
|
|
|
620 |
dup 0 le {
|
|
|
621 |
( **** Error: Cannot find a %%EOF marker anywhere in the file.\n)
|
|
|
622 |
pdfformaterror
|
|
|
623 |
/findxref cvx /syntaxerror signalerror
|
|
|
624 |
} if
|
|
|
625 |
} if
|
|
|
626 |
dup 3 1 roll setfileposition
|
|
|
627 |
% Stack: eofpos
|
|
|
628 |
% Check for whether this is, in fact, a valid PDF file.
|
|
|
629 |
dup PDFfilelen exch sub dup dup 7 gt exch 5 lt or {
|
|
|
630 |
pop true
|
|
|
631 |
} {
|
|
|
632 |
string PDFfile exch readstring pop
|
|
|
633 |
dup (%%EOF\n) eq exch dup (%%EOF\r) eq
|
|
|
634 |
exch dup (%%EOF\r\n) eq exch (%%EOF) eq or or or not
|
|
|
635 |
} ifelse {
|
|
|
636 |
( **** Warning: File has a corrupted %%EOF marker, or garbage after %%EOF.\n)
|
|
|
637 |
pdfformaterror
|
|
|
638 |
} if
|
|
|
639 |
PDFfile exch setfileposition
|
|
|
640 |
% Now read the startxref and xref start position.
|
|
|
641 |
prevline token not { null } if dup type /integertype eq {
|
|
|
642 |
exch pop cvi % xref start position
|
|
|
643 |
exch PDFfile exch setfileposition
|
|
|
644 |
prevline dup (startxref) linene {
|
|
|
645 |
% startxref not on a line by itself. We have found PDF from
|
|
|
646 |
% www.verypdf.com in which the startxref was on the same line as
|
|
|
647 |
% the end of trailer dictionary. Check for this. Note: This
|
|
|
648 |
% violates the spec.
|
|
|
649 |
dup (startxref) search {
|
|
|
650 |
% found startxref - print warning
|
|
|
651 |
pop pop pop % clear strings from search
|
|
|
652 |
( **** Warning: format of the startxref line in this file is invalid.\n)
|
|
|
653 |
pdfformaterror
|
|
|
654 |
} { % no startxref - we have a problem.
|
|
|
655 |
/findxref cvx /syntaxerror signalerror
|
|
|
656 |
} ifelse
|
|
|
657 |
} if
|
|
|
658 |
pop pop
|
|
|
659 |
} { % else, this file has 'startxref #####' format
|
|
|
660 |
(startxref) ne { /findxref cvx /syntaxerror signalerror } if
|
|
|
661 |
cvi % xref start position
|
|
|
662 |
( **** Warning: format of the startxref line in this file is invalid.\n)
|
|
|
663 |
pdfformaterror
|
|
|
664 |
exch PDFfile exch setfileposition
|
|
|
665 |
} ifelse
|
|
|
666 |
} bind def
|
|
|
667 |
/stderrfile (%stderr) (w) file def
|
|
|
668 |
/stderrprint { % <string> stderrprint -
|
|
|
669 |
//stderrfile dup 3 -1 roll writestring flushfile
|
|
|
670 |
} bind def
|
|
|
671 |
/pdfformaterror { % <string> pdfformaterror -
|
|
|
672 |
stderrprint
|
|
|
673 |
/Repaired true store
|
|
|
674 |
} bind def
|
|
|
675 |
|
|
|
676 |
/knownoget_safe
|
|
|
677 |
{ 2 copy knownoget { 3 1 roll pop pop //true } { pop pop //false } ifelse
|
|
|
678 |
} odef
|
|
|
679 |
|
|
|
680 |
/printProducer {
|
|
|
681 |
Trailer /Info { knownoget_safe } stopped { pop pop false } if {
|
|
|
682 |
/Producer knownoget not { null } if
|
|
|
683 |
} {
|
|
|
684 |
null
|
|
|
685 |
} ifelse
|
|
|
686 |
dup null eq {
|
|
|
687 |
pop
|
|
|
688 |
} {
|
|
|
689 |
( **** The file was produced by: \n **** >>>> ) stderrprint
|
|
|
690 |
% Handle a Unicode Producer.
|
|
|
691 |
(\376\377) anchorsearch {
|
|
|
692 |
pop dup length 2 idiv string 0 1 2 index length 1 sub {
|
|
|
693 |
% Stack: origstr newstr i
|
|
|
694 |
1 index exch 3 index 1 index 2 mul 1 add get put
|
|
|
695 |
} for exch pop
|
|
|
696 |
} if
|
|
|
697 |
stderrprint
|
|
|
698 |
( <<<<\n) stderrprint
|
|
|
699 |
} ifelse
|
|
|
700 |
} bind def
|
|
|
701 |
% The TTFWarnList is the list of all TrueType fonts that were not embedded.
|
|
|
702 |
% The UndefProcList collects noisy warnings.
|
|
|
703 |
% This gets rid of many multiple warnings from pdf_font.ps
|
|
|
704 |
/printCollectedWarnings {
|
|
|
705 |
TTFWarnList length 0 gt {
|
|
|
706 |
(\n **** Warning: Fonts with Subtype = /TrueType should be embedded.\n)
|
|
|
707 |
stderrprint
|
|
|
708 |
( The following fonts were not embedded:\n)
|
|
|
709 |
stderrprint
|
|
|
710 |
[ TTFWarnList { pop .namestring (\t\t\t) exch concatstrings (\n) concatstrings } forall ]
|
|
|
711 |
{ lt } .sort { stderrprint } forall
|
|
|
712 |
} if
|
|
|
713 |
UndefProcList length 0 gt {
|
|
|
714 |
(\n **** Embedded font uses undefined procedure\(s\): ) stderrprint
|
|
|
715 |
UndefProcList {
|
|
|
716 |
exch .namestring stderrprint ( ) stderrprint
|
|
|
717 |
=string cvs stderrprint ( times, ) stderrprint
|
|
|
718 |
} forall
|
|
|
719 |
(\n) stderrprint
|
|
|
720 |
} if
|
|
|
721 |
} bind def
|
|
|
722 |
/printrepaired {
|
|
|
723 |
printCollectedWarnings
|
|
|
724 |
(\n **** This file had errors that were repaired or ignored.\n)
|
|
|
725 |
stderrprint
|
|
|
726 |
printProducer
|
|
|
727 |
( **** Please notify the author of the software that produced this\n)
|
|
|
728 |
stderrprint
|
|
|
729 |
( **** file that it does not conform to Adobe's published PDF\n)
|
|
|
730 |
stderrprint
|
|
|
731 |
( **** specification.\n\n)
|
|
|
732 |
stderrprint
|
|
|
733 |
} bind def
|
|
|
734 |
|
|
|
735 |
% Write the outline structure for a file. Uses linkdest (below).
|
|
|
736 |
% omit links to pages that don't exist.
|
|
|
737 |
/writeoutline % <outlinedict> writeoutline -
|
|
|
738 |
{ mark
|
|
|
739 |
|
|
|
740 |
{ { exch 1 add exch /Next knownoget not { exit } if } loop }
|
|
|
741 |
if
|
|
|
742 |
% stack: dict mark count
|
|
|
743 |
dup 0 eq
|
|
|
744 |
{ pop 1 index }
|
|
|
745 |
{ 2 index /Count knownoget { 0 lt { neg } if } if
|
|
|
746 |
/Count exch 3 index
|
|
|
747 |
}
|
|
|
748 |
ifelse { linkdest } stopped
|
|
|
749 |
{
|
|
|
750 |
cleartomark % ignore this link
|
|
|
751 |
( **** Warning: Outline has invalid link that was discarded.\n)
|
|
|
752 |
pdfformaterror
|
|
|
753 |
} {
|
|
|
754 |
/Title oget /Title exch /OUT pdfmark
|
|
|
755 |
}
|
|
|
756 |
ifelse
|
|
|
757 |
/First knownoget
|
|
|
758 |
{ { dup writeoutline /Next knownoget not { exit } if } loop }
|
|
|
759 |
if
|
|
|
760 |
} bind def
|
|
|
761 |
|
|
|
762 |
% Close a PDF file.
|
|
|
763 |
/pdfclose % <dict> pdfclose -
|
|
|
764 |
{ begin
|
|
|
765 |
PDFfile closefile
|
|
|
766 |
end
|
|
|
767 |
} bind def
|
|
|
768 |
|
|
|
769 |
% ======================== Page accessing ======================== %
|
|
|
770 |
|
|
|
771 |
% Get a (possibly inherited) attribute of a page.
|
|
|
772 |
/pget % <pagedict> <key> pget <value> -true-
|
|
|
773 |
% <pagedict> <key> pget -false-
|
|
|
774 |
{ 2 copy knownoget
|
|
|
775 |
{ exch pop exch pop true
|
|
|
776 |
}
|
|
|
777 |
{ exch /Parent knownoget
|
|
|
778 |
{ exch pget }
|
|
|
779 |
{ pop false }
|
|
|
780 |
ifelse
|
|
|
781 |
}
|
|
|
782 |
ifelse
|
|
|
783 |
} bind def
|
|
|
784 |
|
|
|
785 |
% Get the value of a resource on a given page.
|
|
|
786 |
/rget { % <resname> <pagedict> <restype> rget <value> -true-
|
|
|
787 |
% <resname> <pagedict> <restype> rget -false-
|
|
|
788 |
LocalResources 1 index knownoget {
|
|
|
789 |
3 index knownoget
|
|
|
790 |
} {
|
|
|
791 |
false
|
|
|
792 |
} ifelse {
|
|
|
793 |
exch pop exch pop exch pop true
|
|
|
794 |
} {
|
|
|
795 |
exch /Resources pget {
|
|
|
796 |
exch knownoget { exch knownoget } { pop false } ifelse
|
|
|
797 |
} {
|
|
|
798 |
pop pop false
|
|
|
799 |
} ifelse
|
|
|
800 |
} ifelse
|
|
|
801 |
} bind def
|
|
|
802 |
|
|
|
803 |
% Get the total number of pages in the document.
|
|
|
804 |
/pdfpagecount % - pdfpagecount <int>
|
|
|
805 |
{ Trailer /Root oget /Pages oget /Count oget
|
|
|
806 |
} bind def
|
|
|
807 |
|
|
|
808 |
% Find the N'th page of the document by iterating through the Pages tree.
|
|
|
809 |
% The first page is numbered 1.
|
|
|
810 |
/pdffindpageref { % <int> pdffindpage <objref>
|
|
|
811 |
dup Trailer /Root oget /Pages get
|
|
|
812 |
{ % We should be able to tell when we reach a leaf
|
|
|
813 |
% by finding a Type unequal to /Pages. Unfortunately,
|
|
|
814 |
% some files distributed by Adobe lack the Type key
|
|
|
815 |
% in some of the Pages nodes! Instead, we check for Kids.
|
|
|
816 |
dup oforce /Kids knownoget not { exit } if
|
|
|
817 |
exch pop null
|
|
|
818 |
|
|
|
819 |
2 index exch get
|
|
|
820 |
dup oforce dup /Kids known { /Count oget } { pop 1 } ifelse
|
|
|
821 |
% Stack: index kids null noderef count
|
|
|
822 |
dup 5 index ge { pop exch pop exit } if
|
|
|
823 |
5 -1 roll exch sub 4 1 roll pop
|
|
|
824 |
} for exch pop
|
|
|
825 |
% Stack: index null|noderef
|
|
|
826 |
dup null eq { pop pop 1 null exit } if
|
|
|
827 |
} loop
|
|
|
828 |
% Stack: index countleft noderef
|
|
|
829 |
1 index 1 ne { pop pop /pdffindpage cvx /rangecheck signalerror } if
|
|
|
830 |
exch pop
|
|
|
831 |
PageIndex 2 index 1 sub 65533 .min 2 index oforce put
|
|
|
832 |
PageNumbers 1 index oforce 3 index dup 65534 le
|
|
|
833 |
{ put }
|
|
|
834 |
{ pop pop pop } % don't store more than 65534 pagenumbers
|
|
|
835 |
ifelse
|
|
|
836 |
exch pop
|
|
|
837 |
} bind def
|
|
|
838 |
/pdffindpage { % <int> pdffindpage <pagedict>
|
|
|
839 |
pdffindpageref oforce
|
|
|
840 |
} bind def
|
|
|
841 |
|
|
|
842 |
% Find the N'th page of the document.
|
|
|
843 |
% The first page is numbered 1.
|
|
|
844 |
/pdfgetpage % <int> pdfgetpage <pagedict>
|
|
|
845 |
{ PageIndex 1 index 1 sub dup 65533 lt
|
|
|
846 |
{ get }
|
|
|
847 |
{ pop pop null }
|
|
|
848 |
ifelse
|
|
|
849 |
dup null ne
|
|
|
850 |
{ exch pop oforce }
|
|
|
851 |
{ pop pdffindpage }
|
|
|
852 |
ifelse
|
|
|
853 |
} bind def
|
|
|
854 |
|
|
|
855 |
% Find the page number of a page object (inverse of pdfgetpage).
|
|
|
856 |
/pdfpagenumber % <pagedict> pdfpagenumber <int>
|
|
|
857 |
{ % We use the simplest and stupidest of all possible algorithms....
|
|
|
858 |
PageNumbers 1 index .knownget
|
|
|
859 |
{ exch pop
|
|
|
860 |
}
|
|
|
861 |
{ 1 1 PageCount 1 add % will give a rangecheck if not found
|
|
|
862 |
{ dup pdfgetpage oforce 2 index eq { exit } if pop
|
|
|
863 |
}
|
|
|
864 |
for exch pop
|
|
|
865 |
}
|
|
|
866 |
ifelse
|
|
|
867 |
} bind def
|
|
|
868 |
|
|
|
869 |
% Arrange the four elements that define a rectangle into a 'normal' order.
|
|
|
870 |
/normrect_elems % <x1> <y1> <x2> <y2> normrect_elems <llx> <lly> <urx> <ury>
|
|
|
871 |
{
|
|
|
872 |
exch 4 1 roll % <x2> <x1> <y1> <y2>
|
|
|
873 |
2 copy gt { exch } if % <x2> <x1> <lly> <ury>
|
|
|
874 |
4 2 roll 2 copy lt { exch } if % <lly> <ury> <urx> <llx>
|
|
|
875 |
4 1 roll exch % <llx> <lly> <urx> <ury>
|
|
|
876 |
} bind def
|
|
|
877 |
|
|
|
878 |
% Arrange a rectangle into a 'normal' order. I.e the lower left corner
|
|
|
879 |
% followed by the upper right corner.
|
|
|
880 |
/normrect % <rect> normrect <rect>
|
|
|
881 |
{
|
|
|
882 |
aload pop normrect_elems 4 array astore
|
|
|
883 |
} bind def
|
|
|
884 |
|
|
|
885 |
/boxrect % <llx> <lly> <urx> <ury> boxrect <x> <y> <w> <h>
|
|
|
886 |
{ exch 3 index sub exch 2 index sub
|
|
|
887 |
} bind def
|
|
|
888 |
/resolvedest { % <name|string|other> resolvedest <other|null>
|
|
|
889 |
dup type /nametype eq {
|
|
|
890 |
Trailer /Root oget /Dests knownoget {
|
|
|
891 |
exch knownoget not { null } if
|
|
|
892 |
} {
|
|
|
893 |
pop null
|
|
|
894 |
} ifelse
|
|
|
895 |
} {
|
|
|
896 |
dup type /stringtype eq {
|
|
|
897 |
Trailer /Root oget /Names knownoget {
|
|
|
898 |
/Dests knownoget {
|
|
|
899 |
exch nameoget
|
|
|
900 |
} {
|
|
|
901 |
pop null
|
|
|
902 |
} ifelse
|
|
|
903 |
} {
|
|
|
904 |
pop null
|
|
|
905 |
} ifelse
|
|
|
906 |
} if
|
|
|
907 |
} ifelse
|
|
|
908 |
} bind def
|
|
|
909 |
/linkdest { % <link|outline> linkdest
|
|
|
910 |
% ([/Page <n>] /View <view> | ) <link|outline>
|
|
|
911 |
dup /Dest knownoget
|
|
|
912 |
{ resolvedest
|
|
|
913 |
dup type /dicttype eq { /D knownoget not { null } if } if
|
|
|
914 |
dup null eq
|
|
|
915 |
{ pop }
|
|
|
916 |
{ dup 0 oget
|
|
|
917 |
dup type /dicttype eq {
|
|
|
918 |
dup /Type knownoget {
|
|
|
919 |
/Page eq {
|
|
|
920 |
pdfpagenumber
|
|
|
921 |
} if
|
|
|
922 |
} if
|
|
|
923 |
} if
|
|
|
924 |
dup type /integertype ne
|
|
|
925 |
{ pop }
|
|
|
926 |
{ /Page exch 4 -2 roll }
|
|
|
927 |
ifelse
|
|
|
928 |
dup length 1 sub 1 exch getinterval /View exch 3 -1 roll
|
|
|
929 |
}
|
|
|
930 |
ifelse
|
|
|
931 |
}
|
|
|
932 |
if
|
|
|
933 |
} bind def
|
|
|
934 |
% <pagedict> mark ... -proc- -
|
|
|
935 |
/namedactions 8 dict dup begin
|
|
|
936 |
/FirstPage {
|
|
|
937 |
/Page 1 3 -1 roll
|
|
|
938 |
} def
|
|
|
939 |
/LastPage {
|
|
|
940 |
counttomark 2 add index pdfpagecount /Page exch 3 -1 roll
|
|
|
941 |
} def
|
|
|
942 |
/NextPage {
|
|
|
943 |
counttomark 2 add index pdfpagenumber 1 add /Page exch 3 -1 roll
|
|
|
944 |
} def
|
|
|
945 |
/PrevPage {
|
|
|
946 |
counttomark 2 add index pdfpagenumber 1 sub /Page exch 3 -1 roll
|
|
|
947 |
} def
|
|
|
948 |
end readonly def
|
|
|
949 |
% <pagedict> <annotdict> -proc- -
|
|
|
950 |
/annottypes 5 dict dup begin
|
|
|
951 |
/Text {
|
|
|
952 |
mark exch
|
|
|
953 |
{ /Rect /Open /Contents }
|
|
|
954 |
{ 2 copy knownoget { 3 -1 roll } { pop } ifelse }
|
|
|
955 |
forall pop /ANN pdfmark
|
|
|
956 |
} bind def
|
|
|
957 |
/Link {
|
|
|
958 |
mark exch
|
|
|
959 |
dup /C knownoget { /Color exch 3 -1 roll } if
|
|
|
960 |
{ /Rect /Border }
|
|
|
961 |
{ 2 copy knownoget { 3 -1 roll } { pop } ifelse }
|
|
|
962 |
forall dup /A knownoget {
|
|
|
963 |
dup /URI known {
|
|
|
964 |
/A mark 3 2 roll % <<>> /A [ <<action>>
|
|
|
965 |
{ oforce } forall
|
|
|
966 |
.dicttomark
|
|
|
967 |
3 2 roll
|
|
|
968 |
} {
|
|
|
969 |
dup /D knownoget {
|
|
|
970 |
exch pop exch dup length dict copy dup /Dest 4 -1 roll put
|
|
|
971 |
} {
|
|
|
972 |
/N knownoget { % Assume /S /Named
|
|
|
973 |
namedactions exch .knownget { exec } if
|
|
|
974 |
} if
|
|
|
975 |
} ifelse
|
|
|
976 |
} ifelse
|
|
|
977 |
} if
|
|
|
978 |
linkdest pop /LNK pdfmark
|
|
|
979 |
} bind def
|
|
|
980 |
end readonly def
|
|
|
981 |
|
|
|
982 |
% **** The following procedure should not be changed to allow clients
|
|
|
983 |
% **** to directly interface with the constituent procedures. GSview
|
|
|
984 |
% **** and some Artifex customers rely on the pdfshowpage_init,
|
|
|
985 |
% **** pdfshowpage_setpage, pdfshowpage_finish so all logic should be
|
|
|
986 |
% **** implemented in one of those three procedures.
|
|
|
987 |
/pdfshowpage % <pagedict> pdfshowpage -
|
|
|
988 |
{ dup /Page exch store
|
|
|
989 |
pdfshowpage_init
|
|
|
990 |
pdfshowpage_setpage
|
|
|
991 |
pdfshowpage_finish
|
|
|
992 |
} bind def
|
|
|
993 |
|
|
|
994 |
/pdfpagecontents % <pagedict> pdfpagecontents <contents>
|
|
|
995 |
{ } bind def
|
|
|
996 |
|
|
|
997 |
/pdfshowpage_init % <pagedict> pdfshowpage_init <pagedict>
|
|
|
998 |
{ /DSCPageCount DSCPageCount 1 add store
|
|
|
999 |
} bind def
|
|
|
1000 |
|
|
|
1001 |
/.pdfshowpage_Install { % <pagedict> [<prevproc>] .pdfshowpage_Install -
|
|
|
1002 |
exch
|
|
|
1003 |
% We would like to clip to the CropBox here, but the subsequent
|
|
|
1004 |
% initgraphics would override it. Instead, we have to handle it
|
|
|
1005 |
% in graphicsbeginpage.
|
|
|
1006 |
dup /CropBox pget dup {exch pop} if systemdict /UseCropBox known and {
|
|
|
1007 |
dup /CropBox pget pop
|
|
|
1008 |
} {
|
|
|
1009 |
dup /MediaBox pget pop % There has to be a MediaBox
|
|
|
1010 |
} ifelse
|
|
|
1011 |
% stack: [<prevproc>] <pagedict> <Crop|Media Box>
|
|
|
1012 |
exch pop oforce_array normrect % done with the pagedict
|
|
|
1013 |
systemdict /PDFFitPage known {
|
|
|
1014 |
PDFDEBUG { (Fiting PDF to imageable area of the page.) = flush } if
|
|
|
1015 |
currentpagedevice /.HWMargins get aload pop
|
|
|
1016 |
currentpagedevice /PageSize get aload pop
|
|
|
1017 |
3 -1 roll sub 3 1 roll exch sub exch
|
|
|
1018 |
% stack: [<prevproc>] <pagedict> <Crop|Media Box> Xmin Ymin Xmax Ymax
|
|
|
1019 |
PDFDEBUG { ( Translate up by [ ) print 3 index =print (, ) print 2 index =print ( ]) = flush } if
|
|
|
1020 |
3 index 3 index translate % move origin up to imageable area
|
|
|
1021 |
2 index sub exch 3 index sub exch 4 2 roll pop pop
|
|
|
1022 |
% stack: [Box] XImageable YImageable
|
|
|
1023 |
2 index aload pop 2 index sub exch 3 index sub exch 4 2 roll pop pop
|
|
|
1024 |
% stack: [Box] XImageable YImageable XBox YBox
|
|
|
1025 |
3 -1 roll exch div 3 1 roll div .min
|
|
|
1026 |
PDFDEBUG { ( Scale by ) print dup = flush } if
|
|
|
1027 |
dup scale
|
|
|
1028 |
} if
|
|
|
1029 |
% Now translate to the origin given in the Crop|Media Box
|
|
|
1030 |
dup 0 get neg exch 1 get neg translate
|
|
|
1031 |
|
|
|
1032 |
exec
|
|
|
1033 |
} bind def
|
|
|
1034 |
|
|
|
1035 |
/pdfshowpage_setpage { % <pagedict> pdfshowpage_setpage <pagedict>
|
|
|
1036 |
5 dict begin % for setpagedevice
|
|
|
1037 |
% Stack: pagedict
|
|
|
1038 |
% UseCIEColor is always true for PDF; see the comment in runpdf above
|
|
|
1039 |
/UseCIEColor true def
|
|
|
1040 |
currentpagedevice /Orientation 2 index /Rotate pget not { 0 } if 90 idiv
|
|
|
1041 |
% Rotate specifies *clockwise* rotation!
|
|
|
1042 |
neg 3 and def
|
|
|
1043 |
% Stack: pagedict currentpagedict
|
|
|
1044 |
1 index /CropBox pget dup {exch pop} if systemdict /UseCropBox known and {
|
|
|
1045 |
% Set the page size.
|
|
|
1046 |
1 index /CropBox pget pop oforce_elems normrect_elems boxrect
|
|
|
1047 |
2 array astore /PageSize exch def pop pop
|
|
|
1048 |
} {
|
|
|
1049 |
1 index /MediaBox pget {
|
|
|
1050 |
% Set the page size.
|
|
|
1051 |
oforce_elems normrect_elems boxrect
|
|
|
1052 |
2 array astore /PageSize exch def pop pop
|
|
|
1053 |
} if
|
|
|
1054 |
} ifelse
|
|
|
1055 |
% Don't change the page size if we are going to fit the PDF to the page
|
|
|
1056 |
systemdict /PDFFitPage known { currentdict /PageSize undef } if
|
|
|
1057 |
% Let the device know if we will be using PDF 1.4 transparency.
|
|
|
1058 |
% The clist logic may need to adjust the size of bands.
|
|
|
1059 |
1 index pageusestransparency /PageUsesTransparency exch def
|
|
|
1060 |
dup /Install .knownget {
|
|
|
1061 |
% Don't let the Install procedure get more deeply
|
|
|
1062 |
% nested after every page.
|
|
|
1063 |
dup type dup /arraytype eq exch /packedarraytype eq or {
|
|
|
1064 |
dup length 4 eq {
|
|
|
1065 |
dup 2 get /.pdfshowpage_Install load eq {
|
|
|
1066 |
1 get 0 get % previous procedure
|
|
|
1067 |
} if
|
|
|
1068 |
} if
|
|
|
1069 |
} if
|
|
|
1070 |
} {
|
|
|
1071 |
{ }
|
|
|
1072 |
} ifelse 1 array astore
|
|
|
1073 |
2 index exch /.pdfshowpage_Install load /exec load
|
|
|
1074 |
4 packedarray cvx
|
|
|
1075 |
% Stack: pagedict currentpagedict installproc
|
|
|
1076 |
/Install exch def
|
|
|
1077 |
% Stack: pagedict currentpagedict
|
|
|
1078 |
pop currentdict end setpagedevice
|
|
|
1079 |
} bind def
|
|
|
1080 |
|
|
|
1081 |
/pdfshowpage_finish { % <pagedict> pdfshowpage_finish -
|
|
|
1082 |
save /PDFSave exch store
|
|
|
1083 |
/PDFdictstackcount countdictstack store
|
|
|
1084 |
(before exec) VMDEBUG
|
|
|
1085 |
|
|
|
1086 |
% set up color space substitution (this must be inside the page save)
|
|
|
1087 |
pdfshowpage_setcspacesub
|
|
|
1088 |
|
|
|
1089 |
.writepdfmarks {
|
|
|
1090 |
|
|
|
1091 |
% Copy the crop box.
|
|
|
1092 |
dup /CropBox knownoget {
|
|
|
1093 |
oforce_array normrect
|
|
|
1094 |
|
|
|
1095 |
% .pdfshowpage_Install translates the origin -
|
|
|
1096 |
% do same here with the CropBox.
|
|
|
1097 |
|
|
|
1098 |
1 index /CropBox pget dup {exch pop} if systemdict /UseCropBox known and {
|
|
|
1099 |
1 index /CropBox pget pop
|
|
|
1100 |
} {
|
|
|
1101 |
1 index /MediaBox pget pop % There has to be a MediaBox
|
|
|
1102 |
} ifelse
|
|
|
1103 |
oforce_array normrect
|
|
|
1104 |
dup 0 get exch 1 get % [] tx ty
|
|
|
1105 |
2 index 0 get 2 index sub 3 index exch 0 exch put
|
|
|
1106 |
2 index 2 get 2 index sub 3 index exch 2 exch put
|
|
|
1107 |
2 index 1 get 1 index sub 3 index exch 1 exch put
|
|
|
1108 |
2 index 3 get 1 index sub 3 index exch 3 exch put
|
|
|
1109 |
pop pop
|
|
|
1110 |
|
|
|
1111 |
% If the page has been rotated, rotate the CropBox.
|
|
|
1112 |
mark /CropBox 3 -1 roll
|
|
|
1113 |
3 index /Rotate pget {
|
|
|
1114 |
90 idiv 1 and 0 ne {
|
|
|
1115 |
aload pop 4 -2 roll exch 4 2 roll exch 4 array astore
|
|
|
1116 |
} if
|
|
|
1117 |
} if
|
|
|
1118 |
/PAGE pdfmark
|
|
|
1119 |
} if
|
|
|
1120 |
|
|
|
1121 |
% Copy annotations and links.
|
|
|
1122 |
dup /Annots knownoget {
|
|
|
1123 |
|
|
|
1124 |
{ 1 index exch oget
|
|
|
1125 |
dup /Subtype oget annottypes exch .knownget { exec } { pop } ifelse
|
|
|
1126 |
}
|
|
|
1127 |
for pop
|
|
|
1128 |
} if
|
|
|
1129 |
|
|
|
1130 |
} if % end .writepdfmarks
|
|
|
1131 |
|
|
|
1132 |
% Display the actual page contents.
|
|
|
1133 |
6 dict begin
|
|
|
1134 |
/BXlevel 0 def
|
|
|
1135 |
/BGDefault currentblackgeneration def
|
|
|
1136 |
/UCRDefault currentundercolorremoval def
|
|
|
1137 |
%****** DOESN'T HANDLE COLOR TRANSFER YET ******
|
|
|
1138 |
/TRDefault currenttransfer def
|
|
|
1139 |
matrix currentmatrix 2 dict
|
|
|
1140 |
2 index /CropBox knownoget {
|
|
|
1141 |
oforce_elems normrect_elems boxrect
|
|
|
1142 |
4 array astore 1 index /ClipRect 3 -1 roll put
|
|
|
1143 |
} if
|
|
|
1144 |
dictbeginpage setmatrix
|
|
|
1145 |
/DefaultQstate qstate store
|
|
|
1146 |
|
|
|
1147 |
dup % for showing annotations below
|
|
|
1148 |
count 1 sub /pdfemptycount exch store
|
|
|
1149 |
% If the page uses any transparency features, show it within
|
|
|
1150 |
% a transparency group.
|
|
|
1151 |
dup pageusestransparency dup /PDFusingtransparency exch def {
|
|
|
1152 |
% Show the page within a PDF 1.4 device filter.
|
|
|
1153 |
|
|
|
1154 |
/DefaultQstate qstate store % device has changed -- reset DefaultQstate
|
|
|
1155 |
% If the page has a Group, enclose contents in transparency group.
|
|
|
1156 |
% (Adobe Tech Note 5407, sec 9.2)
|
|
|
1157 |
dup /Group knownoget {
|
|
|
1158 |
1 index /CropBox knownoget not {
|
|
|
1159 |
1 index /MediaBox pget pop
|
|
|
1160 |
} if oforce_array normrect .beginformgroup {
|
|
|
1161 |
showpagecontents
|
|
|
1162 |
} stopped {
|
|
|
1163 |
.discardtransparencygroup stop
|
|
|
1164 |
} if .endtransparencygroup
|
|
|
1165 |
} {
|
|
|
1166 |
showpagecontents
|
|
|
1167 |
} ifelse
|
|
|
1168 |
} stopped {
|
|
|
1169 |
% todo: discard
|
|
|
1170 |
.poppdf14devicefilter
|
|
|
1171 |
/DefaultQstate qstate store % device has changed -- reset DefaultQstate
|
|
|
1172 |
stop
|
|
|
1173 |
} if .poppdf14devicefilter
|
|
|
1174 |
/DefaultQstate qstate store % device has changed -- reset DefaultQstate
|
|
|
1175 |
} {
|
|
|
1176 |
showpagecontents
|
|
|
1177 |
} ifelse
|
|
|
1178 |
% check for extra garbage on the ostack and clean it up
|
|
|
1179 |
count pdfemptycount sub dup 0 ne {
|
|
|
1180 |
( **** File did not complete the page properly and may be damaged.\n)
|
|
|
1181 |
pdfformaterror
|
|
|
1182 |
{ pop } repeat
|
|
|
1183 |
} {
|
|
|
1184 |
pop
|
|
|
1185 |
} ifelse
|
|
|
1186 |
% todo: mixing drawing ops outside the device filter could cause
|
|
|
1187 |
% problems, for example with the pnga device.
|
|
|
1188 |
/Annots knownoget { { oforce drawannot } forall } if
|
|
|
1189 |
endpage
|
|
|
1190 |
end % scratch dict
|
|
|
1191 |
% Some PDF files don't have matching q/Q (gsave/grestore) so we need
|
|
|
1192 |
% to clean up any left over dicts from the dictstack
|
|
|
1193 |
countdictstack PDFdictstackcount sub dup 0 ne {
|
|
|
1194 |
( **** Warning: File has imbalanced q/Q operators \(too many q's\)\n)
|
|
|
1195 |
pdfformaterror
|
|
|
1196 |
{ end } repeat
|
|
|
1197 |
} {
|
|
|
1198 |
pop
|
|
|
1199 |
} ifelse
|
|
|
1200 |
(after exec) VMDEBUG
|
|
|
1201 |
Repaired % pass Repaired state around the restore
|
|
|
1202 |
PDFSave restore
|
|
|
1203 |
/Repaired exch def
|
|
|
1204 |
} bind def
|
|
|
1205 |
/showpagecontents { % <pagedict> showpagecontents -
|
|
|
1206 |
gsave % preserve gstate for Annotations later
|
|
|
1207 |
/Contents knownoget not { 0 array } if
|
|
|
1208 |
dup type /arraytype ne { 1 array astore } if {
|
|
|
1209 |
oforce false resolvestream pdfopdict .pdfrun
|
|
|
1210 |
} forall
|
|
|
1211 |
grestore
|
|
|
1212 |
} bind def
|
|
|
1213 |
/processcolorspace { % - processcolorspace <colorspace>
|
|
|
1214 |
% The following is per the PLRM3.
|
|
|
1215 |
currentdevice 1 dict dup /ProcessColorModel dup put .getdeviceparams
|
|
|
1216 |
exch pop exch pop
|
|
|
1217 |
dup type /nametype ne { cvn } if
|
|
|
1218 |
dup { setcolorspace } .internalstopped { pop /DeviceRGB } if
|
|
|
1219 |
} bind def
|
|
|
1220 |
|
|
|
1221 |
% ------ Transparency support ------ %
|
|
|
1222 |
|
|
|
1223 |
% Define minimum PDF version for checking for transparency features.
|
|
|
1224 |
% Transparency is a 1.4 feature however we have seen files that claimed
|
|
|
1225 |
% to be PDF 1.3 with transparency features.
|
|
|
1226 |
/PDFtransparencyversion 1.3 def
|
|
|
1227 |
|
|
|
1228 |
% Determine whether a page might invoke any transparency features:
|
|
|
1229 |
% - Non-default BM, ca, CA, or SMask in an ExtGState
|
|
|
1230 |
% - Image XObject with SMask
|
|
|
1231 |
% Note: we deliberately don't check to see whether a Group is defined,
|
|
|
1232 |
% because Adobe Illustrator 10 (and possibly other applications) define
|
|
|
1233 |
% a page-level group whether transparency is actually used or not.
|
|
|
1234 |
% Ignoring the presence of Group is justified because, in the absence
|
|
|
1235 |
% of any other transparency features, they have no effect.
|
|
|
1236 |
/pageusestransparency { % <pagedict> pageusestransparency <bool>
|
|
|
1237 |
PDFversion PDFtransparencyversion lt NOTRANSPARENCY or {
|
|
|
1238 |
pop false
|
|
|
1239 |
} {
|
|
|
1240 |
false exch {
|
|
|
1241 |
4 dict 1 index resourceusestransparency { pop not exit } if
|
|
|
1242 |
/Parent knownoget not { exit } if
|
|
|
1243 |
} loop
|
|
|
1244 |
} ifelse
|
|
|
1245 |
} bind def
|
|
|
1246 |
|
|
|
1247 |
% Check the Resources of a page or Form. Check for loops in the resource chain.
|
|
|
1248 |
/resourceusestransparency { % <dict> <dict> resourceusestransparency <bool>
|
|
|
1249 |
{ % Use loop to provide an exitable context.
|
|
|
1250 |
/Resources knownoget not { 0 dict } if
|
|
|
1251 |
2 copy known {
|
|
|
1252 |
( **** File has circular references in resource dictionaries.\n)
|
|
|
1253 |
pdfformaterror
|
|
|
1254 |
pop false exit
|
|
|
1255 |
} if
|
|
|
1256 |
2 copy dup put
|
|
|
1257 |
dup /ExtGState knownoget {
|
|
|
1258 |
false exch {
|
|
|
1259 |
exch pop oforce
|
|
|
1260 |
dup /BM knownoget { dup /Normal ne exch /Compatible ne and
|
|
|
1261 |
{ pop not exit } if
|
|
|
1262 |
} if
|
|
|
1263 |
dup /ca knownoget { 1 ne { pop not exit } if } if
|
|
|
1264 |
dup /CA knownoget { 1 ne { pop not exit } if } if
|
|
|
1265 |
dup /SMask knownoget { /None ne { pop not exit } if } if
|
|
|
1266 |
pop
|
|
|
1267 |
} forall { pop true exit } if
|
|
|
1268 |
} if
|
|
|
1269 |
dup /XObject knownoget {
|
|
|
1270 |
false exch {
|
|
|
1271 |
exch pop oforce dup /Subtype get
|
|
|
1272 |
dup /Image eq { 1 index /SMask known { pop pop not exit } if } if
|
|
|
1273 |
/Form eq {
|
|
|
1274 |
3 index exch resourceusestransparency { not exit } if
|
|
|
1275 |
} {
|
|
|
1276 |
pop
|
|
|
1277 |
} ifelse
|
|
|
1278 |
} forall { pop true exit } if
|
|
|
1279 |
} if
|
|
|
1280 |
pop false exit
|
|
|
1281 |
} loop
|
|
|
1282 |
exch pop
|
|
|
1283 |
} bind def
|
|
|
1284 |
|
|
|
1285 |
% ------ ColorSpace substitution support ------ %
|
|
|
1286 |
|
|
|
1287 |
%
|
|
|
1288 |
% <pagedict> pdfshowpage_setcspacesub <pagedict>
|
|
|
1289 |
%
|
|
|
1290 |
% Set up color space substitution for a page. Invocations of this procedure
|
|
|
1291 |
% must be bracketed by the save/restore operation for the page, to avoid
|
|
|
1292 |
% unintended effects on other pages.
|
|
|
1293 |
%
|
|
|
1294 |
% If any color space substitution is used, and the current color space is a
|
|
|
1295 |
% device dependent color space, make sure the current color space is updated.
|
|
|
1296 |
% There is an optimization in the setcolorspace pseudo-operator that does
|
|
|
1297 |
% nothing if both the current and operand color spaces are the same. For
|
|
|
1298 |
% PostScript this optimization is disabled if the UseCIEColor page device
|
|
|
1299 |
% parameter is true. This is not the case for PDF, as performance suffers
|
|
|
1300 |
% significantly on some PDF files if color spaces are set repeatedly. Hence,
|
|
|
1301 |
% if color space substitution is to be used, and the current color space
|
|
|
1302 |
% is a device dependent color space, we must make sure to "transition" the
|
|
|
1303 |
% current color space.
|
|
|
1304 |
%
|
|
|
1305 |
/pdfshowpage_setcspacesub
|
|
|
1306 |
{
|
|
|
1307 |
false
|
|
|
1308 |
{ /DefaultGray /DefaultRGB /DefaultCMYK }
|
|
|
1309 |
{
|
|
|
1310 |
dup 3 index /ColorSpace //rget exec
|
|
|
1311 |
{ resolvecolorspace /ColorSpace defineresource pop }
|
|
|
1312 |
{ pop }
|
|
|
1313 |
ifelse
|
|
|
1314 |
}
|
|
|
1315 |
forall
|
|
|
1316 |
|
|
|
1317 |
% if using color space substitution, "transition" the current color space
|
|
|
1318 |
{
|
|
|
1319 |
currentcolorspace dup length 1 eq % always an array
|
|
|
1320 |
{
|
|
|
1321 |
|
|
|
1322 |
dup /DeviceGray eq 1 index /DeviceRGB eq or 1 index /DeviceCMYK or
|
|
|
1323 |
{ /Pattern setcolorspace setcolorspace }
|
|
|
1324 |
{ pop }
|
|
|
1325 |
ifelse
|
|
|
1326 |
}
|
|
|
1327 |
{ pop }
|
|
|
1328 |
if
|
|
|
1329 |
}
|
|
|
1330 |
if
|
|
|
1331 |
}
|
|
|
1332 |
bind def
|
|
|
1333 |
|
|
|
1334 |
|
|
|
1335 |
|
|
|
1336 |
end % pdfdict
|
|
|
1337 |
.setglobal
|