]> git.lizzy.rs Git - plan9front.git/blob - sys/lib/ghostscript/pdf_main.ps
Import sources from 2011-03-30 iso image - lib
[plan9front.git] / sys / lib / ghostscript / pdf_main.ps
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    0 setobjectformat
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    0                            % Initialize xref table error counter
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            0 3 1 roll           % Set ObjectStream object number = 0
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    0 ne {
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   0 exch { 256 mul 1 index read pop add } repeat
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     0 3 1 roll                  % set stream number = 0
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     0 setxrefentry pop          % set generation number = 0
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    0 2 2 index length 1 sub {
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     0 ne {                              % Skip if object number is free
463       ObjectStream 1 index lget         % Check if object is in objectstream
464       0 eq {    % We only check objects not in an objectstream
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    0 2 index /First knownoget
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       0 1 3 index length 1 sub {
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   0 get
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       0 1 2 index length 1 sub
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     0 .pushpdf14devicefilter {
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             0 get
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