home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / ghostscript / 8.64 / Resource / Init / pdf_main.ps < prev    next >
Encoding:
Text File  |  2009-04-17  |  63.3 KB  |  1,911 lines

  1. %    Copyright (C) 1994, 2000 Aladdin Enterprises.  All rights reserved.
  2. % This software is provided AS-IS with no warranty, either express or
  3. % implied.
  4. % This software is distributed under license and may not be copied,
  5. % modified or distributed except as expressly authorized under the terms
  6. % of the license contained in the file LICENSE in this distribution.
  7. % For more information about licensing, please refer to
  8. % http://www.ghostscript.com/licensing/. For information on
  9. % commercial licensing, go to http://www.artifex.com/licensing/ or
  10. % contact Artifex Software, Inc., 101 Lucas Valley Road #110,
  11. % San Rafael, CA  94903, U.S.A., +1(415)492-9861.
  12.  
  13. % $Id: pdf_main.ps 9382 2009-01-22 01:17:35Z alexcher $
  14. % pdf_main.ps
  15. % PDF file- and page-level operations.
  16.  
  17. /.setlanguagelevel where { pop 2 .setlanguagelevel } if
  18. .currentglobal true .setglobal
  19. /pdfdict where { pop } { /pdfdict 100 dict def } ifelse
  20. pdfdict begin
  21.  
  22. % Patch in an obsolete variable used by some third-party software.
  23. /#? false def
  24.  
  25. % Test whether the current output device handles pdfmark.
  26. /.writepdfmarkdict 1 dict dup /pdfmark null put readonly def
  27. /.writepdfmarks {    % - .writepdfmarks <bool>
  28.   currentdevice //.writepdfmarkdict .getdeviceparams
  29.   mark eq { false } { pop pop true } ifelse
  30.   systemdict /DOPDFMARKS known or 
  31. } bind def
  32.  
  33. % For simplicity, we use a single interpretation dictionary for all
  34. % PDF graphics execution, even though this is too liberal.
  35. /pdfopdict mark
  36.   objopdict { } forall
  37.   drawopdict { } forall
  38.   /endstream { exit } bind
  39.   (%%EOF) cvn { exit } bind        % for filters
  40.   /obj { (   **** Warning: Content stream is not terminated by 'endstream'.\n)
  41.          pdfformaterror pop pop exit
  42.        } bind
  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.   /- { 0  % Bug 690016
  54.        (   **** Warning: Invalid operator '-' is assumed to be a number 0.\n)
  55.        pdfformaterror
  56.      } bind
  57. .dicttomark readonly def
  58.  
  59. % ======================== Main program ======================== %
  60.  
  61. end            % pdfdict
  62. userdict begin
  63.  
  64. /defaultfontname /Times-Roman def
  65.  
  66. % Make sure the registered encodings are loaded, so we don't run the risk
  67. % that some of the indices for their names will overflow the packed
  68. % representation.  (Yes, this is a hack.)
  69. SymbolEncoding pop
  70. DingbatsEncoding pop
  71.  
  72. % Redefine 'run' so it recognizes PDF files.
  73. systemdict begin
  74. /.runps /run load def
  75. /run {
  76.   dup type /filetype ne { (r) file } if
  77.   % skip leading whitespace characters (actually anything less than or equal to <sp>)
  78.   { dup ( ) .peekstring not { false exit } if
  79.     dup 0 get 32 le { pop dup read pop pop } { true exit } ifelse
  80.   } loop
  81.   exch pop
  82.   {
  83.     % Appletalk PAP sends short strings with %! header expecting a response. 
  84.     % 'gv' swallows the %!PS line, then sends DSC comments beginning with %%
  85.     % and also waits for a response. The following avoids those hangs.
  86.     dup 2 string .peekstring pop dup (%!) eq exch (%%) eq or {
  87.       cvx .runps
  88.     } {
  89.       dup 1023 string .peekstring pop dup length 400 ge {
  90.     % "1024 string" exceeds current %stdin buffer
  91.     % Valid PDF file cannot be smaller than 400 bytes.
  92.     (%PDF-) search {
  93.       3 1 roll pop pop
  94.       dup (%!PS) search not {
  95.         length 0 ne { 
  96.           1 index exch readstring pop pop
  97.           (%stderr) (w) file dup 
  98.           (   **** Warning: File has some garbage before %PDF- .\n)
  99.           writestring flushfile
  100.         } { 
  101.           pop
  102.         } ifelse
  103.         dup (%stdin) (r) file eq {
  104.           % Copy PDF from stdin to temporary file then run it.
  105.           null (w+) /.tempfile .systemvar exec exch 3 1 roll
  106.           % stack: tempname stdin tempfile
  107.           64000 string
  108.           {
  109.         % stack: tempname stdin tempfile string
  110.         2 index 1 index readstring
  111.         exch 3 index exch writestring
  112.         not { exit } if
  113.           }
  114.           loop
  115.           pop exch closefile
  116.           % stack: tempname tempfile
  117.           dup 0 setfileposition
  118.           dup runpdf
  119.           closefile deletefile
  120.         } { 
  121.           runpdf
  122.         } ifelse
  123.       } {
  124.         pop pop pop pop cvx .runps % (%!PS) found first
  125.       } ifelse
  126.     } { 
  127.       pop cvx .runps % (%PDF-) not found
  128.     } ifelse
  129.       } { 
  130.     pop cvx .runps   % too short for PDF
  131.       } ifelse
  132.     } ifelse
  133.   } {
  134.     closefile % file was empty
  135.   } ifelse
  136. } bind odef
  137. currentdict /runpdfstring .undef
  138.  
  139.  
  140. /runpdfbegin {        % <file> runpdfbegin - 
  141.    userdict begin
  142.     % It turns out that the PDF interpreter uses memory more
  143.     % effectively if it is run under at least one level of save.
  144.     % This is counter-intuitive, and we don't understand why it happens,
  145.     % but the improvement is significant.
  146.    /PDFTopSave save def
  147.    0 setobjectformat
  148.    /Page# null def
  149.    /Page null def
  150.    /DSCPageCount 0 def
  151.    /PDFSave null def
  152.    GS_PDF_ProcSet begin
  153.    pdfdict begin
  154.    pdfopen begin
  155. } bind def
  156.  
  157. /runpdfpagerange {    % - runpdfpagerange <firstpage#> <lastpage#>
  158.    /FirstPage where 
  159.     { pop FirstPage dup pdfpagecount gt
  160.       { (\nRequested FirstPage is greater than the number of pages in the file: ) print
  161.         pdfpagecount = flush
  162.       } if
  163.     } {
  164.       1
  165.     } ifelse
  166.    /LastPage where { pop LastPage pdfpagecount .min } { pdfpagecount } ifelse
  167.    1 index 1 index gt
  168.     { (   No pages will be processed \(FirstPage > LastPage\).) = flush }
  169.     { QUIET not
  170.       { (Processing pages ) print 1 index =only ( through ) print dup =only
  171.         (.) = flush
  172.       }
  173.      if
  174.     }
  175.    ifelse
  176. } bind def
  177.  
  178. /dopdfpages {   % firstpage# lastpage# dopdfpages -
  179.   << /PDFScanRules //true >> setuserparams    % set scanning rules for PDF vs. PS
  180.   << /RenderTTNotdef systemdict 
  181.      /RENDERTTNOTDEF get >> setuserparams    % Should we render TT /.notdef
  182.   1 exch
  183.     { dup /Page# exch store
  184.       QUIET not { (Page ) print dup == flush } if
  185.       pdfgetpage pdfshowpage
  186.     } for
  187.   << /PDFScanRules //null >> setuserparams    % restore scanning rules for PS
  188. } bind def
  189.  
  190. /runpdfend {
  191.    Repaired { printrepaired } if
  192.    currentdict pdfclose
  193.    end            % temporary dict
  194.    end            % pdfdict
  195.    end            % GS_PDF_ProcSet
  196.    PDFTopSave restore
  197.    end            % userdict
  198.    2 vmreclaim        % couldn't hurt
  199. } bind def
  200.  
  201.  
  202. % Copy default subfile to a temporary file and return the file name
  203. % as a PostScript name to protect it from restore. Return null if
  204. % there's no default subfile.
  205. %
  206. % - pdf_collection_files /temp_file_name | null
  207. /pdf_collection_files {
  208.   //null
  209.   Trailer /Root oget /Collection knownoget {
  210.     /D knownoget { % We have default document in the collection
  211.       Trailer /Root oget /Names knownoget {
  212.         /EmbeddedFiles knownoget {
  213.           exch nameoget dup //null ne {
  214.             /EF knownoget {
  215.               /F knownoget {
  216.                 //true resolvestream    % null strm
  217.                 //null (w) /.tempfile   % null strm (name) null (w) /.tempfile
  218.                 .systemvar exec         % null strm (name) file
  219.                 3 -1 roll               % null (name) file strm
  220.                 32768 string            % null (name) file strm (buf)
  221.                 { 3 copy readstring     % null (name) file strm (buf) file (data) bool
  222.                   3 1 roll              % null (name) file strm (buf) bool file (data)
  223.                   writestring           % null (name) file strm (buf) bool
  224.                   not { exit } if
  225.                 } loop                  
  226.                 pop closefile           % null (name) file
  227.                 closefile               % null (name)
  228.                 exch pop cvn            % /name
  229.               } if
  230.             } if
  231.           } {
  232.             pop
  233.           } ifelse
  234.         } {
  235.           pop
  236.         } ifelse
  237.       } {
  238.         pop
  239.       } ifelse
  240.     } if
  241.   } if
  242. } bind def
  243.  
  244. /runpdf {        % <file> runpdf -
  245.   //runpdfbegin exec
  246.   //pdf_collection_files exec
  247.   dup type /nametype ne {
  248.     copy_trailer_attrs
  249.     //runpdfpagerange exec
  250.     //dopdfpages exec
  251.   } if
  252.   //runpdfend exec
  253.   dup type /nametype eq {
  254.     .namestring dup (r) file
  255.     //runpdfbegin exec
  256.     copy_trailer_attrs
  257.     //runpdfpagerange exec
  258.     //dopdfpages exec
  259.     //runpdfend exec
  260.     deletefile
  261.   } {
  262.     pop
  263.   } ifelse
  264. } bind def
  265.  
  266. currentdict /pdf_collection_files .undef
  267.  
  268. end            % systemdict
  269. % Redefine the procedure that the C code uses for running piped input.
  270. % It is OK to use { (%stdin) run } here, because a startjob cannot occur.
  271. /.runstdin {
  272.   { (%stdin) run } execute0
  273. } bind def
  274.  
  275. end            % userdict
  276. pdfdict begin
  277.  
  278. % ======================== File parsing ======================== %
  279.  
  280. % Read the cross-reference and trailer sections.
  281.  
  282. /traileropdict mark
  283.   (<<) cvn { /dictlevelcount dictlevelcount 1 add store mark } bind
  284.   (>>) cvn { { .dicttomark } stopped {
  285.           (   **** File has unbalanced >> in trailer.\n) pdfformaterror
  286.              } if
  287.          /dictlevelcount dictlevelcount 1 sub def
  288.              dictlevelcount 0 eq { exit } if
  289.            } bind
  290.   ([) cvn { mark } bind        % ditto
  291.   (]) cvn dup load
  292. %  /true true        % see .pdfexectoken in pdf_base.ps
  293. %  /false false        % ibid.
  294. %  /null null        % ibid.
  295.   /R { /resolveR cvx 3 packedarray cvx } bind    % see Objects below
  296. .dicttomark readonly def
  297.  
  298. % Because of EOL conversion, lines with fixed contents might be followed
  299. % by one or more blanks.
  300. /lineeq            % <filestr> <conststr> lineeq <bool>
  301.  { anchorsearch
  302.     { pop { ( ) anchorsearch not { () eq exit } if pop } loop }
  303.     { pop false }
  304.    ifelse
  305.  } bind def
  306. /linene { lineeq not } bind def
  307.  
  308.  %  Read original version (pre PDF 1.5) of the xref table.
  309.  %  Note:  The position is the location of 'xref'.  The current PDFfile
  310.  %  position is just after the 'XREF'.
  311. /readorigxref        % <pos> readorigxref <trailerdict>
  312.  {
  313.    pop                % We do not need the position.
  314.    0                % Initialize xref table error counter
  315.    { PDFfile token pop        % first object # or trailer
  316.      dup /trailer eq { pop exit } if
  317.      PDFfile pdfstring readline pop
  318.      token pop            % entry count
  319.      % remaining must be whitespace only (otherwise this xref Size was invalid.
  320.      exch dup length 0 ne {
  321.        false 1 index { 32 gt { pop true exit } if } forall {
  322.          (   **** Warning: xref subsection header has extra characters.\n)
  323.          pdfformaterror
  324.          /setxrefentry cvx /syntaxerror signalerror
  325.        } if
  326.      } if
  327.      pop            % remove last
  328.         % This section might be adding new objects:
  329.         % ensure that Objects and Generations are big enough.
  330.         % stack: <err count> <first obj> <entry count>
  331.      2 copy add growPDFobjects
  332.      {                % stack: <err count> <obj num>
  333.         % Read xref line
  334.        PDFfile 20 string readstring pop  % always read 20 chars.
  335.        token pop        % object position
  336.        exch token pop        % generation #
  337.        exch token pop        % n or f
  338.        exch            % stack: <err count> <obj#> <loc> <gen#> <tag> <remainder of line>
  339.        dup length 0 ne {
  340.          % check to make sure trailing garbage is just white space
  341.      dup { 32 gt { 5 -1 roll 1 add 5 1 roll } if } forall   % bump error count on garbage
  342.        } if
  343.        pop            % Stack: <err count> <obj#> <loc> <gen#> <tag>
  344.        dup /n eq {        % xref line tag is /n
  345.      pop            % pop dup of line tag
  346.      0 3 1 roll        % Set ObjectStream object number = 0
  347.      //false setxrefentry    % Save xref entry, don't change existing entries
  348.      3 -1 roll pop        % Remove ObjectStream object onumber
  349.        }
  350.        {            % xref line tag was not /n
  351.      /f ne            % verify that the tag was /f
  352.          { /setxrefentry cvx /syntaxerror signalerror
  353.      } if
  354.        } ifelse
  355.        pop pop            % pop <obj location> and <gen num>
  356.        % stack: <err count> <obj num>
  357.        1 add            % increment object number
  358.      } repeat
  359.      pop            % pop <obj #>
  360.    } loop
  361.    0 ne {
  362.      (   **** Warning:  length of some xref entries is not equal to 20 bytes.\n)
  363.      pdfformaterror
  364.    } if
  365.    /dictlevelcount 0 def
  366.    PDFfile traileropdict .pdfrun
  367.  } bind def
  368.  
  369.  % This dicitonary is used to read the xref dictionary.  It should work for
  370.  % reading any dictionary.  dictlevelcount must contain 0.
  371. /xrefopdict mark
  372.   (<<) cvn { /dictlevelcount dictlevelcount 1 add def mark } bind
  373.   (>>) cvn { .dicttomark /dictlevelcount dictlevelcount 1 sub def
  374.            dictlevelcount 0 eq { exit} if } bind
  375.   ([) cvn { mark } bind        % ditto
  376.   (]) cvn dup load
  377. %  /true true        % see .pdfexectoken in pdf_base.ps
  378. %  /false false        % ibid.
  379. %  /null null        % ibid.
  380.   /R { /resolveR cvx 3 packedarray cvx } bind    % see Objects below
  381. .dicttomark readonly def
  382.  
  383. % Get a variable length positive integer value from a stream.  A value
  384. % of zero is returned if the count is zero.
  385. /getintn {    % <stream> <count> getintn int
  386.   0 exch { 256 mul 1 index read pop add } repeat
  387.   exch pop            % Discard stream
  388. } bind def
  389.  
  390. % This array contains handlers for processing the different types of
  391. % entries in the XRef stream.
  392. % Stack: <Xrefdict> <xref stream> <Index array> <pair loc> <obj num>
  393. %      <field 2> <field 3>
  394. % The handlers leave the stack unchanged.
  395. /xref15entryhandlers [
  396.   {    % XRef entry type 0 - free or f type xref entry
  397. %    (free ) print
  398. %    (obj num: ) print 2 index pdfstring cvs print ( ) print
  399. %    (loc: ) print 1 index pdfstring cvs print ( ) print
  400. %    (gen: ) print dup === flush
  401.   } bind        % Do nothing for free xref entries
  402.     % XRef entry type 1 - normal or n type xref entry
  403.   {    % field 2 = obj loc, field 3 = gen num
  404. %    (normal ) print
  405. %    (obj num: ) print 2 index pdfstring cvs print ( ) print
  406. %    (loc: ) print 1 index pdfstring cvs print ( ) print
  407. %    (gen: ) print dup === flush
  408.     0 3 1 roll            % set stream number = 0
  409.     //false setxrefentry
  410.     3 -1 roll pop        % remove stream number
  411.   } bind
  412.     % XRef entry type 2 - compressed object type xref entry
  413.   {    % field 2 = object stream num, field 3 = index into object stream
  414. %    (Compressed objects: ) print
  415. %    (obj num: ) print 2 index pdfstring cvs print ( ) print
  416. %    (field 2: ) print 1 index pdfstring cvs print ( ) print
  417. %    (field 3: ) print dup === flush
  418.     0 //false setxrefentry pop    % set generation number = 0
  419.   } bind
  420. ] def
  421.  
  422.  %  Read the PDF 1.5 version of the xref table.
  423.  %  Note:  The position is the location of the start of the dictionary object
  424.  %  In PDF 1.5, the XRef dictionary also serves as the trailer dictionary
  425. /readpdf15xref        % <pos> readpdf15xref <trailerdict>
  426.  {
  427.    PDFfile exch setfileposition        % move to start of object
  428.        % Get object number, revision, and 'obj' and discard
  429.    PDFfile token pop pop
  430.    PDFfile token pop pop
  431.    PDFfile token pop pop
  432.     % Get the XRef dicitionary
  433.    /dictlevelcount 0 def PDFfile xrefopdict .pdfrun
  434.     % Verify that we have an XRef dictionary
  435.    dup /Type get /XRef ne {
  436.      /readpdf15xref cvx /syntaxerror signalerror
  437.    } if
  438.        % Ensure that we we have room in the objects array, etc.
  439.    dup /Size get growPDFobjects
  440.     % Create a stream for the XRef data
  441.    PDFfile token pop pop        % Skip over 'stream'
  442.    dup stream false resolvestream
  443.        % Stack: <XRefdict> <xref stream>
  444.     % The Index array defines the ranges of object numbers in the
  445.     % XRef stream.  Each value pair is consists of starting object
  446.     % number and the count of consecutive objects.
  447.     % Get the Index array, if present
  448.    1 index /Index .knownget not {    % If no Index array ...
  449.      [ 0 3 index /Size get ]        % Default = [ 0 Size ]
  450.    } if
  451.     % Loop through the Index array
  452.    0 2 2 index length 1 sub {
  453.     % Get start and end of object range
  454.      2 copy get                % Start of the range
  455.      dup 3 index 3 index 1 add get     % Number of entries in range
  456.          % Loop through the range of object numbers
  457.      add 1 sub 1 exch {            % Form end of range, set increment = 1
  458.     % Stack: <Xrefdict> <xref stream> <Index array> <pair loc> <obj num>
  459.     % Get xref parameters.  Note:  The number of bytes for each parameter
  460.     % is defined by the entries in the W array.
  461.        4 index /W get aload pop        % Get W array values
  462.            % The first field indicates type of entry.  Get first field value.
  463.     % If the num. of bytes for field 1 is 0 then default field value is 1
  464.        3 -1 roll dup 0 eq { pop 1 } { 6 index exch getintn } ifelse
  465.     % Get the handler for the xref entry type.  We will execute the
  466.     % handler after we get the other two field values.
  467.        xref15entryhandlers exch get
  468.        3 -1 roll 6 index exch getintn    % Get second field
  469.        3 -1 roll 6 index exch getintn    % Get third field
  470.        3 -1 roll exec            % Execute Xref entry handler
  471.        pop pop pop            % Remove field values and obj num
  472.      } for                % Loop through Xref entries
  473.      pop                % Remove Index array pair loc
  474.    } for                % Loop through Index array entries
  475.    pop pop                % Remove Index array and xref stream
  476.  } bind def
  477.  
  478. % Read the cross-reference table.
  479. % <pos> is the position either from the startxref statement or the /Prev
  480. % entry in the prior trailer dictionary.
  481. /readxref        % <pos> readxref <trailerdict>
  482.  {
  483.    PDFoffset add PDFfile exch
  484.    % Check that the given location is within the file.
  485.    dup PDFfilelen gt {
  486.        (   **** Warning:  Specified xref location is beyond end of file.\n)
  487.        pdfformaterror
  488.        /readxref cvx /invalidaccess signalerror
  489.    } if
  490.    setfileposition
  491.         % In some PDF files, this position actually points to
  492.         % white space before the xref line.  Skip over this here.
  493.    {
  494.      PDFfile fileposition PDFfile read pop 32 gt { exit } if pop
  495.    } loop
  496.    dup        % Make copy of the file position (before last char was read).
  497.    PDFfile exch setfileposition
  498.         % The PDF specification says that the 'xref' must be on a line
  499.         % by itself. The code here formerly used readline and linene to
  500.         % check this. However, Acrobat Reader only requires the line to
  501.         % begin with 'xref', and there are enough applications producing
  502.         % non-compliant PDF files that we have to do this too.
  503.    PDFfile pdfstring 0 4 getinterval readstring pop
  504.    (xref) eq
  505.    {
  506.      readorigxref    % 'xref' -> original xref table
  507.      % if hybrid-reference PDF, also fetch the entries 
  508.      % found in the XRef stream pointed by /XRefStm
  509.      dup /XRefStm knownoget {
  510.        readpdf15xref pop
  511.      } if
  512.    }
  513.    { readpdf15xref }    % otherwise assume PDF 1.5 xref stream
  514.    ifelse
  515.  } bind def
  516.  
  517. % Open a PDF file and read the header, trailer, and cross-reference.
  518. /pdfopen {        % <file> pdfopen <dict>
  519.     % Color space substitution in PDF is handled somewhat differently
  520.     % than in PostScript. A given device color space will be substituted
  521.     % if the corresponding "Default..." entry exists in the Page's
  522.     % Resource dictionary (which might be inhereted); there is no
  523.     % UseCIEColor to enable/disable color mapping.
  524.     %
  525.     % This behavior is achieved by always setting UseCIEColor to true
  526.     % in the page device dictionary. If the value of this parameter was
  527.     % originally false (i.e.: the output device does not perform color
  528.     % space substitution by default), the instances DefaultGray,
  529.     % DefaultRGB, and DefaultCMYK of the (local) ColorSpace category
  530.     % are redefined to be DeviceGray, DeviceRGB, and DeviceCMYK,
  531.     % respectively. This is not done if UseCIEColor is true by default,
  532.     % as in that case color substitution is presumably desired even
  533.     % if the file does not request it.
  534.    currentpagedevice /UseCIEColor .knownget dup { pop } if not
  535.     { .currentglobal false .setglobal
  536.       /DefaultGray { /DeviceGray } cvlit /ColorSpace defineresource pop
  537.       /DefaultRGB { /DeviceRGB } cvlit /ColorSpace defineresource pop
  538.       /DefaultCMYK { /DeviceCMYK } cvlit /ColorSpace defineresource pop
  539.       .setglobal
  540.     }
  541.    if
  542.   pdfopenfile begin
  543.   pdfopencache
  544.   currentdict end
  545. } bind def
  546.  
  547. /copy_trailer_attrs {  % - copy_trailer_attrs -
  548.   writeoutputintents
  549.   .writepdfmarks {
  550.     % Copy bookmarks (outline) to the output.
  551.     Trailer /Root oget /Outlines knownoget {
  552.       /First knownoget {
  553.     { dup writeoutline /Next knownoget not { exit } if } loop
  554.       } if
  555.     } if
  556.   } if        % end .writepdfmarks
  557. } bind def
  558.  
  559. % Verify that each entry in the xref table is pointing at an object with
  560. % the correct object number and generation number.
  561. /verify_xref                % - verify_xref -
  562. { PDFfilelen
  563.   1 1 Objects llength 1 sub    % stack: filesize 1 1 <number of objects - 1>
  564.   {    % Check if the object is free (i.e. not used).  The values in
  565.     % Generations is the generation number plus 1.  If the value in
  566.     % Generations is zero then the object is free.
  567.     % Stack:  <filesize> <obj num>
  568.     Generations 1 index lget         % Get the genration number
  569.     0 ne {                % Skip if object number is free
  570.       ObjectStream 1 index lget     % Check if object is in objectstream
  571.       0 eq {    % We only check objects not in an objectstream
  572.         {    % Use stop context since we may get an error if object is invalid
  573.           dup Objects exch lget     % Get the object location
  574.       PDFoffset add dup 3 index ge    % Compare object location to file size
  575.       { pop true }            % Rebuild if location not in file
  576.       { PDFfile exch setfileposition % Go to the object location
  577.         true            % Stack:  <filesize> <obj num> <true>
  578.         PDFfile token pop        % Read object number from file
  579.         2 index eq {        % Verify object number
  580.           PDFfile token pop        % Read generation number from file
  581.           Generations 3 index    % Get specified generaton number
  582.           lget 1 sub        % Gen numbs are stored with 1 added.
  583.           eq {             % Verify generation number
  584.             PDFfile token pop
  585.             /obj eq { % Verify 'obj' text
  586.           pop false        % We have valid object, do not rebuild
  587.             } if
  588.           } if
  589.         } if
  590.       } ifelse
  591.     } .internalstopped
  592.     { true } if            % If we stop then we need to rebuild
  593.     % Stack:  <filesize> <obj num> <need rebuild flag>
  594.     { 
  595.       (   **** Warning:  File has an invalid xref entry:  )
  596.       pdfformaterror
  597.       pdfstring cvs pdfformaterror
  598.       (.  Rebuilding xref table.\n) pdfformaterror
  599.       search_objects
  600.       exit
  601.     } if                % If the entry is invalid
  602.       } {
  603.           % The object is in an object stream.  We currently do not rebuild
  604.           % objects in an object stream.  So If we find one, then abort the
  605.           % verification of the xref table entries.
  606.     pop exit            % Pop object number and then exit loop
  607.       } ifelse                % If not in an object stream
  608.     } if                % If object entry is not free
  609.     pop                    % Remove object number
  610.   } for
  611.   pop                    % Remove the size of the file
  612. } bind odef
  613.  
  614. /pdfopencache {        % - pdfopencache -
  615.     % Create and initialize some caches.
  616.   /PageCount pdfpagecount def
  617.   /PageNumbers PageCount 65534 .min dict def
  618.   /PageIndex PageCount 65534 .min array def
  619. } bind def
  620.  
  621. /pdfopenfile {        % <file> pdfopenfile <dict>
  622.    pdfdict readonly pop        % can't do it any earlier than this
  623.    15 dict begin
  624.    /LocalResources 0 dict def
  625.    /DefaultQstate //null def    % establish binding
  626.    /Printed where { pop } {
  627.         % Guess whether the output device is a printer.
  628.      /Printed currentpagedevice /OutputFile known def
  629.    } ifelse
  630.    /PSLevel1 where { pop } { /PSLevel1 false def } ifelse
  631.    % NB: PDFfile is used outside of the PDF code to determine that a
  632.    % PDF job is being processed; to not change or hide this key.
  633.    cvlit /PDFfile exch def
  634.    /PDFsource PDFfile def
  635.    /Repaired false def
  636.    currentglobal true .setglobal globaldict begin
  637.    /UndefProcList 0 dict def
  638.    end .setglobal
  639.    PDFfile dup 0 setfileposition
  640.    0 () /SubFileDecode filter   % to avoid file closure
  641.    pdfstring readstring pop
  642.    (%PDF-) search not {/pdfopen cvx /syntaxerror signalerror} if
  643.    length /PDFoffset exch def pop
  644.    % some badly formed PDF's (Visioneer) have something other than EOL
  645.    % after the version number. If we get an error, shorten the string
  646.    % and try again.
  647.    false exch        % error encountered
  648.    { { cvr } stopped
  649.      { exch pop true exch 0 1 index length 1 sub dup 0 eq
  650.        { pop 0 exit } if    % exit if string now empty
  651.        getinterval        % trim character from right end and retry
  652.      }
  653.      { exch {
  654.          (   **** Warning: PDF version number not followed by EOL.\n)
  655.          pdfformaterror
  656.        }
  657.        if exit
  658.      }
  659.      ifelse
  660.    } loop
  661.  
  662.    /PDFversion exch def
  663.     % Read the last cross-reference table.
  664.    count /pdfemptycount exch def
  665.    /Trailer << >> def        % Initialize to an emptry dict.
  666.    { initPDFobjects findxref readxref } .internalstopped {
  667.      recover_xref_data        % Read failed.  Attempt to recover xref data.
  668.      search_trailer        % Search for the primary trailer
  669.    } {
  670.      /Trailer exch def        % Save trailer dict after first xref table
  671.     % Read any previous cross-reference tables.  When we are done,
  672.     % verify that the entries in the xref tables are valid if NoVerifyXref
  673.     % is not defined.
  674.      Trailer
  675.      { /Prev knownoget not {    % If no previous xref table then ...
  676.          /NoVerifyXref where { pop } { verify_xref } ifelse exit
  677.        } if
  678.        { readxref } .internalstopped {
  679.          recover_xref_data    % Read failed.  Attempt to recover xref data.
  680.      exit            % Exit loop since recover gets all obj data.
  681.        } if              % If readxref stopped
  682.        % The PDF spec. says that each trailer dict should contain the required
  683.        % entries.  However we have seen a PDF file that only has a Prev entry in
  684.        % the initial trailer dict.  Acrobat complains but it accepts these files.
  685.        % To work with these files, we are copying any entries which we find in
  686.        % a previous trailer dict which are not present in the initial dict.
  687.        dup {
  688.          Trailer 2 index known {
  689.            pop pop              % discard if key already present
  690.          } {
  691.            Trailer 3 1 roll put % add key if not present
  692.          } ifelse
  693.        } forall
  694.      } loop            % Loop to previous trailer
  695.    } ifelse            % Ifelse readxref stopped
  696.  
  697.    % Scan numbers in the range 2147483648..4294967295 in Encrypt dictionary
  698.    % as unsigned integers for compatibility with Acrobat Reader. Bug 689010.
  699.    << /PDFScanUnsigned //true >> setuserparams
  700.    { Trailer /Encrypt knownoget {
  701.        pop
  702.        pdf_process_Encrypt    % signal error
  703.      } if
  704.    } stopped
  705.    << /PDFScanUnsigned //false >> setuserparams
  706.    { stop } if
  707.  
  708.    % Check for recursion in the page tree. Bug 689954, MOAB-06-01-2007
  709.    verify_page_tree
  710.  
  711.    currentdict end
  712.  } bind def
  713.  
  714. % Look for [\r\n]%%EO from the current position of the file.
  715. % Return the position of %%EO if found or -1 .
  716. /findeof {  % <file> find_eof <file> <position>
  717.   -1 exch
  718.   {
  719.     dup bytesavailable 4 lt { exit } if
  720.     dup 0 (%%EO) /SubFileDecode filter flushfile
  721.     dup dup fileposition 5 sub setfileposition
  722.     dup 5 string readstring not { pop exit } if
  723.     dup (\r%%EO) eq exch (\n%%EO) eq or {
  724.       dup fileposition 4 sub
  725.       3 1 roll exch pop
  726.     } if
  727.   } loop
  728.   exch
  729. } bind def
  730.  
  731. % Skip backward over the %%EOF at the end of the PDF file, and read
  732. % the preceding startxref line.  The PDF specification unambiguously
  733. % requires that the %%EOF appear on a line by itself, and that the
  734. % startxref and the following position value appear on separate lines;
  735. % however, some applications truncate the %%EOF to %%EO, and/or put the
  736. % startxref and the following value on the same line.
  737. % There seems to be no limit on the amount of garbage that can be
  738. % appended to the PDF file. Current record (60K) belongs to
  739. % PDF-Out (v 2.0 - 35). We start the search for %%EO from the last 1024
  740. % bytes and continue from the beginning of the file.
  741. /findxref {        % - findxref <xrefpos>
  742.   PDFfile dup dup dup 0 setfileposition bytesavailable
  743.   dup /PDFfilelen exch def
  744.     % Find the last %%EOF string (within 1024 bytes)
  745.   1024 sub PDFoffset .max
  746.   setfileposition findeof                  % search the last 1024 bytes
  747.   dup 0 le {
  748.     pop
  749.     dup PDFoffset setfileposition findeof  % search from the beginnibg
  750.     dup 0 le {
  751.        (   **** Error: Cannot find a %%EOF marker anywhere in the file.\n)
  752.        pdfformaterror
  753.        /findxref cvx /syntaxerror signalerror
  754.     } if
  755.   } if
  756.   dup 3 1 roll setfileposition
  757.         % Stack: eofpos
  758.     % Check for whether this is, in fact, a valid PDF file.
  759.   dup PDFfilelen exch sub dup dup 7 gt exch 5 lt or {
  760.     pop true
  761.   } {
  762.     string PDFfile exch readstring pop
  763.     dup (%%EOF\n) eq exch dup (%%EOF\r) eq
  764.     exch dup (%%EOF\r\n) eq exch (%%EOF) eq or or or not
  765.   } ifelse {
  766.     (   **** Warning: File has a corrupted %%EOF marker, or garbage after %%EOF.\n)
  767.     pdfformaterror
  768.   } if
  769.   PDFfile exch setfileposition
  770.     % Now read the startxref and xref start position.
  771.   prevline token not { null } if dup type /integertype eq {
  772.     exch pop cvi        % xref start position
  773.     exch PDFfile exch setfileposition
  774.     prevline dup (startxref) linene {
  775.       % startxref not on a line by itself.  We have found PDF from
  776.       % www.verypdf.com in which the startxref was on the same line as
  777.       % the end of trailer dictionary.  Check for this.  Note:  This
  778.       % violates the spec.
  779.       dup (startxref) search {
  780.     % found startxref - print warning
  781.     pop pop pop             % clear strings from search
  782.         (   **** Warning: format of the startxref line in this file is invalid.\n)
  783.         pdfformaterror
  784.       } {                % no startxref - we have a problem.
  785.         /findxref cvx /syntaxerror signalerror
  786.       } ifelse
  787.     } if
  788.     pop pop
  789.   } {    % else, this file has 'startxref #####' format
  790.     (startxref) ne { /findxref cvx /syntaxerror signalerror } if
  791.     cvi        % xref start position
  792.     (   **** Warning: format of the startxref line in this file is invalid.\n)
  793.     pdfformaterror
  794.     exch PDFfile exch setfileposition
  795.   } ifelse
  796. } bind def
  797. /stderrfile (%stderr) (w) file def
  798. /stderrprint {                % <string> stderrprint -
  799.   //stderrfile dup 3 -1 roll writestring flushfile
  800. } bind def
  801. /pdfformaterror {    % <string> pdfformaterror -
  802.   stderrprint
  803.   /Repaired true store
  804. } bind def
  805.  
  806. /knownoget_safe
  807. { 2 copy knownoget { 3 1 roll pop pop //true } { pop pop //false } ifelse
  808. } odef
  809.  
  810. /printProducer {
  811.   Trailer /Info { knownoget_safe } stopped { pop pop false } if {
  812.     /Producer knownoget not { null } if
  813.   } {
  814.     null
  815.   } ifelse
  816.   dup null eq {
  817.     pop
  818.   } {
  819.     (   **** The file was produced by: \n   **** >>>> ) stderrprint
  820.     % Handle a Unicode Producer.
  821.     (\376\377) anchorsearch {
  822.       pop dup length 2 idiv string 0 1 2 index length 1 sub {
  823.         % Stack: origstr newstr i
  824.     1 index exch 3 index 1 index 2 mul 1 add get put
  825.       } for exch pop
  826.     } if
  827.     stderrprint
  828.     ( <<<<\n) stderrprint
  829.   } ifelse
  830. } bind def
  831. % The UndefProcList collects noisy warnings.
  832. % This gets rid of many multiple warnings from pdf_font.ps
  833. /printCollectedWarnings {
  834.    UndefProcList length 0 gt {
  835.       (\n   **** Embedded font uses undefined procedure\(s\):  ) stderrprint
  836.       UndefProcList {
  837.          exch .namestring stderrprint ( ) stderrprint
  838.      =string cvs stderrprint ( times, ) stderrprint
  839.       } forall 
  840.       (\n) stderrprint
  841.    } if
  842. } bind def
  843. /printrepaired {
  844.    printCollectedWarnings
  845.    (\n   **** This file had errors that were repaired or ignored.\n)
  846.   stderrprint
  847.   printProducer
  848.   (   **** Please notify the author of the software that produced this\n)
  849.   stderrprint
  850.   (   **** file that it does not conform to Adobe's published PDF\n)
  851.   stderrprint
  852.   (   **** specification.\n\n)
  853.   stderrprint
  854. } bind def
  855.  
  856. % Write the outline structure for a file.  Uses linkdest (below).
  857. % omit links to pages that don't exist.
  858. /writeoutline        % <outlinedict> writeoutline -
  859.  { mark
  860.    0 2 index /First knownoget
  861.     { { exch 1 add exch /Next knownoget not { exit } if } loop }
  862.    if
  863.         % stack: dict mark count
  864.    dup 0 eq
  865.     { pop 1 index }
  866.     { 2 index /Count knownoget { 0 lt { neg } if } if
  867.       /Count exch 3 index
  868.     }
  869.     ifelse
  870.     {
  871.       dup /A knownoget {
  872.         dup /URI known {
  873.           /A mark 3 2 roll    % <<>> /A [ <<action>>
  874.           { oforce } forall
  875.           .dicttomark
  876.           3 2 roll
  877.         } {
  878.           dup /D knownoget {
  879.             exch pop exch dup length dict copy dup /Dest 4 -1 roll put
  880.           } {
  881.             /N knownoget {                % Assume /S /Named
  882.                namedactions exch .knownget { exec } if
  883.              } if
  884.           } ifelse
  885.         } ifelse
  886.       } if
  887.       linkdest
  888.     } stopped
  889.     {
  890.       cleartomark    % ignore this link
  891.       (   **** Warning: Outline has invalid link that was discarded.\n)
  892.       pdfformaterror
  893.     } {
  894.       /Title oget /Title exch /OUT pdfmark
  895.     }
  896.    ifelse
  897.    /First knownoget
  898.     { { dup writeoutline /Next knownoget not { exit } if } loop }
  899.    if
  900.  } bind def
  901.  
  902. % Close a PDF file.
  903. /pdfclose        % <dict> pdfclose -
  904.  { begin
  905.    PDFfile closefile
  906.    end
  907.  } bind def
  908.  
  909. % ======================== Page accessing ======================== %
  910.  
  911. % Get a (possibly inherited) attribute of a page.
  912. /pget            % <pagedict> <key> pget <value> -true-
  913.             % <pagedict> <key> pget -false-
  914.  {
  915.    2 copy knownoget
  916.     { exch pop exch pop true }
  917.     { exch /Parent knownoget
  918.       { exch pget }
  919.     % finally see if the key is (misplaced) in the Root Catalog dict
  920.       { dup Trailer /Root oget exch knownoget dup {
  921.       3 -1 roll (   **** Warning:  The /) pdfformaterror 50 string cvs pdfformaterror
  922.       ( key is missing from the Page tree.\n) pdfformaterror
  923.         }
  924.     { exch pop }
  925.     ifelse
  926.       }
  927.       ifelse
  928.     }
  929.    ifelse
  930.  } bind def
  931.  
  932. % Get the value of a resource on a given page.
  933. /rget {            % <resname> <pagedict> <restype> rget <value> -true-
  934.             % <resname> <pagedict> <restype> rget -false-
  935.   LocalResources 1 index knownoget {
  936.      3 index knownoget
  937.   } {
  938.     false
  939.   } ifelse {
  940.     exch pop exch pop exch pop true
  941.   } {
  942.     exch /Resources pget {
  943.       exch knownoget { exch knownoget } { pop false } ifelse
  944.     } {
  945.       pop pop false
  946.     } ifelse
  947.   } ifelse
  948. } bind def
  949.  
  950. % Get the total number of pages in the document.
  951. /pdfpagecount        % - pdfpagecount <int>
  952.  { Trailer /Root oget /Pages oget
  953.    dup /Count knownoget {
  954.      dup 0 le {
  955.        pop (   **** Warning:  Invalid Page count.\n) pdfformaterror
  956.        % find the last page and use that as the Count
  957.        1 1 999999999 {
  958.          dup pdffindpage?
  959.      exch pop
  960.          //null eq { exit } { pop } ifelse
  961.        } for
  962.        1 sub        % decrement to last page that we were able to find
  963.        2 copy /Count exch put
  964.      } if
  965.      exch pop
  966.    } {
  967.        dup /Type oget /Page eq {
  968.          << exch 1 array astore /Kids exch /Count 1 /Type /Pages >>
  969.          Trailer /Root oget /Pages 3 -1 roll put
  970.          1
  971.          (   **** Warning:  No /Pages node. The document root directly point a page.\n)
  972.          pdfformaterror
  973.      } {
  974.        (   **** Warning:  Page count not found; assuming 1.\n)
  975.        pdfformaterror
  976.        pop 1 
  977.      } ifelse
  978.    } ifelse
  979.  } bind def
  980.  
  981. % Check for loops in the 'page tree' but accept an acyclic graph.
  982. % - verify_page_tree -
  983. /verify_page_tree { 
  984.   Trailer /Root oget /Pages oget
  985.   10 dict begin
  986.   /verify_page_tree_recursive {
  987.     dup 1 def
  988.     dup /Kids knownoget {
  989.       { oforce
  990.         currentdict 1 index known {
  991.           (   **** Error: there's a loop in the page tree. Giving up.\n) pdfformaterror
  992.           /verify_page_tree cvx /syntaxerror signalerror
  993.         } if
  994.         verify_page_tree_recursive
  995.       } forall
  996.     } if
  997.     currentdict exch undef
  998.   } def
  999.   verify_page_tree_recursive
  1000.   end
  1001. } bind def
  1002.  
  1003. /pdffindpage? {        % <int> pdffindpage? 1 null     (page not found)
  1004.             %  <int> pdffindpage? 1 noderef (page found)
  1005.             %  <int> pdffindpage? 0 null    (Error: page not found)
  1006.   Trailer /Root oget /Pages get
  1007.     {        % We should be able to tell when we reach a leaf
  1008.         % by finding a Type unequal to /Pages.  Unfortunately,
  1009.         % some files distributed by Adobe lack the Type key
  1010.         % in some of the Pages nodes!  Instead, we check for Kids.
  1011.       dup oforce /Kids knownoget not { exit } if
  1012.       exch pop null
  1013.       0 1 3 index length 1 sub {
  1014.          2 index exch get
  1015.      dup oforce dup /Kids known { /Count oget } { pop 1 } ifelse
  1016.         % Stack: index kids null noderef count
  1017.      dup 5 index ge { pop exch pop exit } if
  1018.      5 -1 roll exch sub 4 1 roll pop
  1019.       } for exch pop
  1020.         % Stack: index null|noderef
  1021.       dup null eq { pop pop 1 null exit } if
  1022.     } loop
  1023. } bind def
  1024.  
  1025. % Find the N'th page of the document by iterating through the Pages tree.
  1026. % The first page is numbered 1.
  1027. /pdffindpageref {        % <int> pdffindpage <objref>
  1028.   dup pdffindpage?
  1029.         % Stack: index countleft noderef
  1030.    1 index 1 ne { pop pop /pdffindpage cvx /rangecheck signalerror } if
  1031.    exch pop
  1032.    PageIndex 2 index 1 sub 65533 .min 2 index oforce put
  1033.    PageNumbers 1 index oforce 3 index dup 65534 le
  1034.     { put }
  1035.     { pop pop pop }    % don't store more than 65534 pagenumbers
  1036.    ifelse
  1037.    exch pop
  1038. } bind def
  1039. /pdffindpage {        % <int> pdffindpage <pagedict>
  1040.   pdffindpageref oforce
  1041. } bind def
  1042.  
  1043. % Find the N'th page of the document.
  1044. % The first page is numbered 1.
  1045. /pdfgetpage        % <int> pdfgetpage <pagedict>
  1046.  { PageIndex 1 index 1 sub dup 65533 lt
  1047.     { get }
  1048.     { pop pop null }
  1049.    ifelse
  1050.    dup null ne
  1051.     { exch pop oforce }
  1052.     { pop pdffindpage }
  1053.    ifelse
  1054.  } bind def
  1055.  
  1056. % Find the page number of a page object (inverse of pdfgetpage).
  1057. /pdfpagenumber        % <pagedict> pdfpagenumber <int>
  1058.  {    % We use the simplest and stupidest of all possible algorithms....
  1059.    PageNumbers 1 index .knownget
  1060.     { exch pop
  1061.     }
  1062.     { 1 1 PageCount 1 add    % will give a rangecheck if not found
  1063.        { dup pdfgetpage oforce 2 index eq { exit } if pop
  1064.        }
  1065.       for exch pop
  1066.     }
  1067.    ifelse
  1068.  } bind def
  1069.  
  1070. % Arrange the four elements that define a rectangle into a 'normal' order.
  1071. /normrect_elems   % <x1> <y1> <x2> <y2> normrect_elems <llx> <lly> <urx> <ury>
  1072. {
  1073.     exch 4 1 roll            % <x2> <x1> <y1> <y2>
  1074.     2 copy gt { exch } if        % <x2> <x1> <lly> <ury>
  1075.     4 2 roll 2 copy lt { exch } if    % <lly> <ury> <urx> <llx>
  1076.     4 1 roll exch            % <llx> <lly> <urx> <ury>
  1077. } bind def
  1078.  
  1079. % Arrange a rectangle into a 'normal' order.  I.e the lower left corner
  1080. % followed by the upper right corner.
  1081. /normrect     % <rect> normrect <rect>
  1082. {
  1083.     aload pop normrect_elems 4 array astore
  1084. } bind def
  1085.  
  1086. /fix_empty_rect_elems % </Name> <x1> <y1> <x2> <y2> fix_empty_rect_elems <x1> <y1> <x2'> <y2'>
  1087. {  dup 3 index eq { //true } { 1 index 4 index eq } ifelse {
  1088.      pop pop pop pop
  1089.      (   **** Warning:  File has an empty ) pdfformaterror pdfstring cvs pdfformaterror
  1090.      (. Using the current page size instead.\n) pdfformaterror
  1091.      0 0 currentpagedevice /PageSize get aload pop
  1092.    } {
  1093.      5 -1 roll pop
  1094.    } ifelse
  1095. } bind def
  1096.  
  1097. /boxrect        % <llx> <lly> <urx> <ury> boxrect <x> <y> <w> <h>
  1098.  { exch 3 index sub exch 2 index sub
  1099.  } bind def
  1100. /resolvedest {        % <name|string|other> resolvedest <other|null>
  1101.   dup type /nametype eq {
  1102.     Trailer /Root oget /Dests knownoget {
  1103.       exch knownoget not { null } if
  1104.     } {
  1105.       pop null
  1106.     } ifelse
  1107.   } {
  1108.     dup type /stringtype eq {
  1109.       Trailer /Root oget /Names knownoget {
  1110.     /Dests knownoget {
  1111.       exch nameoget
  1112.     } {
  1113.       pop null
  1114.     } ifelse
  1115.       } {
  1116.     pop null
  1117.       } ifelse
  1118.     } if
  1119.   } ifelse
  1120. } bind def
  1121.  
  1122. % Procedures to do the necessary transformations of view destinations
  1123. % <PDF2PS_matrix> <rot> <view> -- <view'>
  1124. /viewdestprocs 8 dict dup begin
  1125.     /Fit  { exch pop exch pop } bind def
  1126.     /FitH {
  1127.     aload pop
  1128.     0 4 -1 roll 1 and 0 eq { exch } if
  1129.     4 -1 roll transform exch pop
  1130.     2 array astore
  1131.     } bind def
  1132.     /FitV {
  1133.     aload pop
  1134.     0 4 -1 roll 1 and 0 ne { exch } if
  1135.     4 -1 roll transform pop
  1136.     2 array astore
  1137.     } bind def
  1138.     /FitB  /Fit  load def
  1139.     /FitBH /FitH load def
  1140.     /FitBV /FitV load def
  1141.     /XYZ  {
  1142.     aload pop
  1143.     3 1 roll
  1144.     2 copy 7 -1 roll 1 and 0 ne { exch } if    4 2 roll    % odd rotation switches x<->y
  1145.     2 { dup null eq { pop 0 } if exch } repeat        % replace nulls with 0
  1146.     7 -1 roll transform                    % transform coordinates
  1147.     2 { 3 -1 roll null eq { pop null } if exch } repeat % put the nulls back
  1148.     3 -1 roll
  1149.     4 array astore
  1150.     } bind def
  1151.     /FitR {
  1152.     exch pop
  1153.     aload pop
  1154.     2 { 5 index transform 4 2 roll } repeat normrect_elems
  1155.     5 array astore
  1156.     exch pop
  1157.     } bind def
  1158. end readonly def
  1159.  
  1160. /linkdest {        % <link|outline> linkdest
  1161.             %   ([/Page <n>] /View <view> | ) <link|outline>
  1162.   dup /Dest knownoget
  1163.     { resolvedest
  1164.       dup type /dicttype eq { /D knownoget not { null } if } if
  1165.       dup null eq
  1166.        { pop }
  1167.        { dup 0 oget
  1168.      false % don't have a page# and transformation matrix (yet)
  1169.      1 index type /dicttype eq {
  1170.        1 index /Type knownoget {
  1171.              /Page eq {
  1172.            pop % the "false" flag
  1173.            dup pdf_cached_PDF2PS_matrix exch
  1174.            dup /Rotate pget not { 0 } if 90 idiv exch
  1175.                pdfpagenumber
  1176.                true % now we have a page# and a transformation matrix
  1177.              } if
  1178.            } if
  1179.          } if
  1180.      % stack: <link|outline> <dest>    ( <PDF2PS_matrix> <rot>    <page#>    true  |     <page> false )
  1181.      {
  1182.        /Page exch 6    2 roll
  1183.        % stack: [/Page <page#>] <link|outline> <dest> <PDF2PS_matrix> <rot>
  1184.        3 -1 roll dup length 1    sub 1 exch getinterval /View 4 1 roll
  1185.        % stack: [/Page <page#>] <link|outline> /View <PDF2PS_matrix> <rot> <view>
  1186.        //viewdestprocs 1 index 0 get get exec
  1187.        3 -1 roll
  1188.      } { 
  1189.        pop
  1190.        dup length 1 sub 1 exch getinterval /View exch 3 -1 roll
  1191.      } ifelse
  1192.        }
  1193.       ifelse
  1194.     }
  1195.    if
  1196. } bind def
  1197. % <pagedict> mark ... -proc- <page#> <error>
  1198. /namedactions 8 dict dup begin
  1199.   /FirstPage { 1 //false } def
  1200.   /LastPage { pdfpagecount //false } def
  1201.   /NextPage { counttomark 2 add index pdfpagenumber 1 add dup pdfpagecount gt } bind def
  1202.   /PrevPage { counttomark 2 add index pdfpagenumber 1 sub dup 1 lt } bind def
  1203. end readonly def
  1204. % <pagedict> <annotdict> -proc- -
  1205. /annottypes 5 dict dup begin
  1206.   /Text {
  1207.     mark exch
  1208.      { /Rect /Open /Contents }
  1209.      { 2 copy knownoget { 3 -1 roll } { pop } ifelse }
  1210.     forall pop /ANN pdfmark
  1211.   } bind def
  1212.   /Link {
  1213.     mark exch
  1214.     dup /C knownoget { /Color exch 3 -1 roll } if
  1215.      { /Rect /Border }
  1216.      { 2 copy knownoget { 3 -1 roll } { pop } ifelse }
  1217.     forall dup /A knownoget {
  1218.       dup /URI known {
  1219.         /A mark 3 2 roll    % <<>> /A [ <<action>>
  1220.         { oforce } forall
  1221.         .dicttomark
  1222.         3 2 roll
  1223.       } {
  1224.         dup /D knownoget {
  1225.       exch pop exch dup length dict copy dup /Dest 4 -1 roll put
  1226.         } {
  1227.       /N knownoget {        % Assume /S /Named
  1228.          namedactions exch .knownget {
  1229.                exec {
  1230.                  pop
  1231.                  (   **** Warning: Ignoring a named action pointing out of the document page range.\n)
  1232.                  pdfformaterror
  1233.                } {
  1234.                  /Page exch 3 -1 roll
  1235.                } ifelse
  1236.              } if
  1237.       } if
  1238.         } ifelse
  1239.       } ifelse
  1240.     } if
  1241.     linkdest pop /LNK pdfmark
  1242.   } bind def
  1243. end readonly def
  1244.  
  1245. % **** The following procedure should not be changed to allow clients
  1246. % **** to directly interface with the constituent procedures. GSview
  1247. % **** and some Artifex customers rely on the pdfshowpage_init,
  1248. % **** pdfshowpage_setpage, pdfshowpage_finish so all logic should be
  1249. % **** implemented in one of those three procedures.
  1250. /pdfshowpage        % <pagedict> pdfshowpage -
  1251.  { dup /Page exch store
  1252.    pdfshowpage_init 
  1253.    pdfshowpage_setpage 
  1254.    pdfshowpage_finish
  1255.  } bind def
  1256.  
  1257. /pdfpagecontents    % <pagedict> pdfpagecontents <contents>
  1258.  { } bind def
  1259.  
  1260. /pdfshowpage_init     % <pagedict> pdfshowpage_init <pagedict>
  1261.  { /DSCPageCount DSCPageCount 1 add store
  1262.  } bind def
  1263.  
  1264. /get_media_box { % <pagedict> get_media_box <box>
  1265.   /MediaBox pget not {
  1266.     (   **** Page has no /MediaBox attribute. Using the current page size.\n)
  1267.     pdfformaterror
  1268.     [ 0 0 currentpagedevice /PageSize get aload pop ]
  1269.   } if
  1270. } bind def
  1271.  
  1272. % Compute the matrix that transforms the PDF->PS "default" user space
  1273. /pdf_PDF2PS_matrix {    % <pdfpagedict> -- matrix
  1274.   matrix currentmatrix matrix setmatrix exch
  1275.   % stack: savedCTM <pdfpagedict>
  1276.   dup /CropBox pget dup {exch pop} if //systemdict /UseCropBox known and {
  1277.     /CropBox 2 copy pget pop
  1278.   } {
  1279.     /MediaBox 1 index get_media_box
  1280.   } ifelse
  1281.   % stack: savedCTM <pdfpagedict> /Crop|MediaBox <Crop|Media Box>
  1282.   oforce_elems normrect_elems fix_empty_rect_elems 4 array astore
  1283.   //systemdict /PDFFitPage known {
  1284.     PDFDEBUG { (Fiting PDF to imageable area of the page.) = flush } if
  1285.     currentpagedevice /.HWMargins get aload pop
  1286.     currentpagedevice /PageSize get aload pop
  1287.     % Adjust PageSize and .HWMargins for the page portrait/landscape orientation
  1288.     2 copy gt
  1289.     7 index aload pop 3 -1 roll sub 3 1 roll exch sub exch
  1290.     10 index /Rotate pget not { 0 } if 90 idiv 1 and 0 ne { exch } if
  1291.     gt
  1292.     ne {
  1293.       2 copy ne {
  1294.         % rotate the .HWMargins
  1295.         2 copy lt {
  1296.       6 2 roll 4 -1 roll 6 -2 roll
  1297.         } {
  1298.       6 2 roll 4  1 roll 6 -2 roll
  1299.         } ifelse
  1300.         % rotate the page dimensions
  1301.         exch
  1302.       } if
  1303.     } if
  1304.     3 -1 roll sub 3 1 roll exch sub exch
  1305.     % stack: savedCTM <pdfpagedict> <Crop|Media Box> Xmin Ymin Xmax Ymax
  1306.     PDFDEBUG { (    Translate up by [ ) print 3 index =print (, ) print 2 index =print ( ]) = flush } if
  1307.     3 index 3 index translate        % move origin up to imageable area
  1308.     2 index sub exch 3 index sub exch 4 2 roll pop pop
  1309.         % stack: savedCTM <pdfpagedict> [Box] XImageable YImageable
  1310.     2 index aload pop 2 index sub exch 3 index sub exch 4 2 roll pop pop
  1311.     5 index /Rotate pget not { 0 } if 90 idiv 1 and 0 ne { exch } if
  1312.         % stack: savedCTM <pdfpagedict> [Box] XImageable YImageable XBox YBox
  1313.     3 -1 roll exch div 3 1 roll div .min
  1314.     PDFDEBUG { (    Scale by ) print dup = flush } if
  1315.   } {
  1316.     //systemdict /NoUserUnit .knownget not { false } if {
  1317.       1
  1318.     } {
  1319.       1 index /UserUnit knownoget {
  1320.         PDFDEBUG { (Scaling due to UserUnit by ) print dup = flush } if
  1321.       } {
  1322.         1
  1323.       } ifelse
  1324.     } ifelse
  1325.   } ifelse
  1326.   % stack: savedCTM <pdfpagedict> [Box] scale
  1327.   dup scale
  1328.   % Rotate according to /Rotate
  1329.   aload pop boxrect
  1330.   {
  1331.     {     pop pop }
  1332.     { -90 rotate pop neg 0 translate }
  1333.     { 180 rotate neg exch neg exch translate }
  1334.     {  90 rotate neg 0 exch translate pop }
  1335.   }
  1336.   5 index /Rotate pget not { 0 } if
  1337.   PDFDEBUG { dup 0 ne { (Rotating by ) print dup =print ( degrees.) = flush } if } if
  1338.   90 idiv 3 and get exec
  1339.   % Now translate to the origin given in the Crop|Media Box
  1340.   exch neg exch neg translate
  1341.   % stack: savedCTM <pdfpagedict>
  1342.   pop
  1343.   matrix currentmatrix exch setmatrix
  1344. } bind def
  1345.  
  1346. % Cache the matrix that transforms the PDF->PS "default" user space
  1347. % into <pdfpagedict> under the key //PDF2PS_matrix_key, then return it
  1348. /PDF2PS_matrix_key (PDF->PS matrix) cvn def
  1349. /pdf_cached_PDF2PS_matrix {  % <pdfpagedict> -- <PDF2PS_matrix>
  1350.   dup //PDF2PS_matrix_key .knownget {
  1351.     exch pop
  1352.   } {
  1353.     dup dup pdf_PDF2PS_matrix //PDF2PS_matrix_key exch put
  1354.     //PDF2PS_matrix_key get
  1355.   } ifelse
  1356. } bind def
  1357. currentdict /PDF2PS_matrix_key undef
  1358.  
  1359. /.pdfshowpage_Install {    % <pagedict> [<prevproc>] .pdfshowpage_Install -
  1360.   0 get exec
  1361.   pdf_cached_PDF2PS_matrix concat
  1362. } bind def
  1363.  
  1364. /pdfshowpage_setpage {    % <pagedict> pdfshowpage_setpage <pagedict>
  1365.   6 dict begin        % for setpagedevice
  1366.     % Stack: pdfpagedict
  1367.   % UseCIEColor is always true for PDF; see the comment in runpdf above
  1368.   /UseCIEColor true def
  1369.   /Orientation 0 def
  1370.   currentpagedevice
  1371.     % Stack: pdfpagedict currentpagedevicedict
  1372.   1 index /CropBox pget dup {exch pop} if //systemdict /UseCropBox known and {
  1373.     /CropBox 2 index /CropBox pget % will use the CropBox
  1374.   } {
  1375.     /MediaBox 2 index get_media_box true % will use the MediaBox
  1376.   } ifelse
  1377.   {
  1378.     oforce_elems normrect_elems fix_empty_rect_elems boxrect 4 2 roll pop pop
  1379.     3 index /Rotate pget not { 0 } if 90 idiv 1 and 0 ne { exch } if
  1380.     % stack: pdfpagedict currentpagedevicedict boxwidth boxheight
  1381.     //systemdict /PDFFitPage known {
  1382.       % Preserve page size,
  1383.       % but choose portrait/landscape depending on box width:height ratio
  1384.       % (if box width == height, select portrait orientation)
  1385.       gt
  1386.       1 index /PageSize get aload pop
  1387.       2 copy gt
  1388.       4 -1 roll ne { exch } if
  1389.     } {
  1390.       % Set the page size.
  1391.       //systemdict /NoUserUnit .knownget not { false } if not {
  1392.         3 index /UserUnit knownoget {
  1393.           dup 4 -1 roll mul 3 1 roll mul
  1394.         } if
  1395.       } if
  1396.     } ifelse
  1397.     2 array astore /PageSize exch def
  1398.   } {
  1399.     pop % pops /Crop|MediaBox
  1400.   } ifelse
  1401.   % Determine the number of spot colors used on the page.  Note: This searches
  1402.   % the pages resources.  It may be high if a spot color is in a resource but
  1403.   % is not actually used on the page.
  1404.   /PageSpotColors 2 index countspotcolors def
  1405.  
  1406.   % Let the device know if we will be using PDF 1.4 transparency.
  1407.   % The clist logic may need to adjust the size of bands.
  1408.   1 index pageusestransparency /PageUsesTransparency exch def
  1409.   dup /Install .knownget {
  1410.             % Don't let the Install procedure get more deeply
  1411.             % nested after every page.
  1412.       dup type dup /arraytype eq exch /packedarraytype eq or {
  1413.     dup length 4 eq {
  1414.       dup 2 get /.pdfshowpage_Install load eq {
  1415.         1 get 0 get    % previous procedure
  1416.       } if
  1417.     } if
  1418.       } if
  1419.   } {
  1420.     { }
  1421.   } ifelse 1 array astore
  1422.   2 index exch /.pdfshowpage_Install load /exec load
  1423.   4 packedarray cvx
  1424.     % Stack: pagedict currentpagedict installproc
  1425.   /Install exch def
  1426.     % Stack: pagedict currentpagedict
  1427.   pop currentdict end setpagedevice
  1428. } bind def
  1429.  
  1430. /.free_page_resources {   % - .free_page_resources -
  1431.   Page /Resources pget {
  1432.     /Shading knownoget {
  1433.       { dup type /dicttype eq {
  1434.           dup /.shading_dict known {
  1435.             dup /.shading_dict undef
  1436.           } if
  1437.         } if
  1438.         pop pop
  1439.       } forall
  1440.     } if
  1441.   } if
  1442. } bind def
  1443.  
  1444. /pdfshowpage_finish {    % <pagedict> pdfshowpage_finish -
  1445.    save /PDFSave exch store
  1446.    /PDFdictstackcount countdictstack store
  1447.    (before exec) VMDEBUG
  1448.  
  1449.    % set up color space substitution (this must be inside the page save)
  1450.    pdfshowpage_setcspacesub
  1451.  
  1452.   .writepdfmarks {
  1453.  
  1454.     % Copy the crop box.
  1455.     dup /CropBox pget {
  1456.         % .pdfshowpage_Install transforms the user space -
  1457.         % do same here with the CropBox.
  1458.       oforce_elems
  1459.       2 { Page pdf_cached_PDF2PS_matrix transform 4 2 roll } repeat
  1460.       normrect_elems /CropBox 5 1 roll fix_empty_rect_elems 4 array astore
  1461.       mark /CropBox 3 -1 roll
  1462.       /PAGE pdfmark
  1463.     } if
  1464.  
  1465.     % Copy annotations and links.
  1466.     dup /Annots knownoget {
  1467.       0 1 2 index length 1 sub
  1468.        { 1 index exch oget
  1469.          dup type /dicttype eq {
  1470.            dup /Subtype oget annottypes exch .knownget { exec } { pop } ifelse
  1471.          } {
  1472.            pop
  1473.          } ifelse
  1474.        }
  1475.       for pop
  1476.     } if
  1477.  
  1478.   } if        % end .writepdfmarks
  1479.  
  1480.     % Display the actual page contents.
  1481.    6 dict begin
  1482.    /BXlevel 0 def
  1483.    /BGDefault currentblackgeneration def
  1484.    /UCRDefault currentundercolorremoval def
  1485.     %****** DOESN'T HANDLE COLOR TRANSFER YET ******
  1486.    /TRDefault currenttransfer def
  1487.   matrix currentmatrix 2 dict
  1488.   2 index /CropBox pget {
  1489.     oforce_elems normrect_elems boxrect
  1490.     4 array astore 1 index /ClipRect 3 -1 roll put
  1491.   } if
  1492.   dictbeginpage setmatrix
  1493.   /DefaultQstate qstate store
  1494.  
  1495.   count 1 sub /pdfemptycount exch store
  1496.     % If the page uses any transparency features, show it within
  1497.     % a transparency group.
  1498.   dup pageusestransparency dup /PDFusingtransparency exch def {
  1499.     % Show the page within a PDF 1.4 device filter.
  1500.     0 .pushpdf14devicefilter {
  1501.       /DefaultQstate qstate store        % device has changed -- reset DefaultQstate
  1502.       % If the page has a Group, enclose contents in transparency group.
  1503.       % (Adobe Tech Note 5407, sec 9.2)
  1504.       dup /Group knownoget {
  1505.     1 index /CropBox pget {
  1506.           /CropBox exch
  1507.         } {
  1508.       1 index get_media_box /MediaBox exch
  1509.     } ifelse
  1510.         oforce_elems normrect_elems fix_empty_rect_elems 4 array astore .beginformgroup {
  1511.       showpagecontents
  1512.     } stopped {
  1513.       .discardtransparencygroup stop
  1514.     } if .endtransparencygroup
  1515.       } {
  1516.     showpagecontents
  1517.       } ifelse
  1518.     } stopped {
  1519.       % todo: discard
  1520.       .poppdf14devicefilter 
  1521.       /DefaultQstate qstate store    % device has changed -- reset DefaultQstate
  1522.       stop
  1523.     } if .poppdf14devicefilter
  1524.     /DefaultQstate qstate store    % device has changed -- reset DefaultQstate
  1525.   } {
  1526.     showpagecontents
  1527.   } ifelse
  1528.   .free_page_resources
  1529.   % todo: mixing drawing ops outside the device filter could cause
  1530.   % problems, for example with the pnga device.
  1531.   endpage
  1532.   end            % scratch dict
  1533.   % Indicate that the number of spot colors is unknown in case the next page
  1534.   % imaged is a PS file.
  1535.   << /PageSpotColors -1 >> .setpagedevice
  1536.   % Some PDF files don't have matching q/Q (gsave/grestore) so we need
  1537.   % to clean up any left over dicts from the dictstack
  1538.   countdictstack PDFdictstackcount sub dup 0 ne { 
  1539.     (   **** Warning: File has imbalanced q/Q operators \(too many q's\)\n)
  1540.     pdfformaterror
  1541.     { end } repeat
  1542.   } {
  1543.     pop
  1544.   } ifelse
  1545.   (after exec) VMDEBUG
  1546.   Repaired        % pass Repaired state around the restore
  1547.   PDFSave restore
  1548.   /Repaired exch def
  1549. } bind def
  1550.  
  1551. % Display the contents of a page (including annotations).
  1552. /showpagecontents {    % <pagedict> showpagecontents -
  1553.   dup        % Save the pagedict for the Annotations
  1554.   count 1 sub  /pdfemptycount exch store
  1555.   gsave        % preserve gstate for Annotations later
  1556.   /Contents knownoget not { 0 array } if
  1557.   dup type /arraytype ne { 1 array astore } if {
  1558.     oforce false resolvestream pdfopdict .pdfrun
  1559.   } forall
  1560.   % check for extra garbage on the ostack and clean it up
  1561.   count pdfemptycount sub dup 0 ne {
  1562.     (   **** File did not complete the page properly and may be damaged.\n)
  1563.     pdfformaterror
  1564.     { pop } repeat
  1565.   } {
  1566.     pop
  1567.   } ifelse
  1568.   grestore
  1569.   % Draw the annotations
  1570.   //systemdict /ShowAnnots .knownget not { //true } if {
  1571.     /Annots knownoget {
  1572.       { oforce
  1573.         dup //null ne {
  1574.           drawannot
  1575.         } {
  1576.           pop
  1577.         } ifelse
  1578.       } forall
  1579.     } if
  1580.   } if
  1581.   //systemdict /ShowAcroForm .knownget { //true eq } { //false } ifelse {
  1582.     Trailer /Root oget /AcroForm knownoget { draw_acro_form } if
  1583.   } if
  1584. } bind def
  1585.  
  1586. /processcolorspace {    % - processcolorspace <colorspace>
  1587.     % The following is per the PLRM3.
  1588.   currentdevice 1 dict dup /ProcessColorModel dup put .getdeviceparams
  1589.   exch pop exch pop
  1590.   dup type /nametype ne { cvn } if
  1591.   dup { setcolorspace } .internalstopped { pop /DeviceRGB } if
  1592. } bind def
  1593.  
  1594. % ------ Transparency support ------ %
  1595.  
  1596. % Define minimum PDF version for checking for transparency features.
  1597. % Transparency is a 1.4 feature however we have seen files that claimed
  1598. % to be PDF 1.2 with transparency features. Bug 689288.
  1599. /PDFtransparencyversion 1.2 def
  1600.  
  1601. % Determine whether a page might invoke any transparency features:
  1602. %    - Non-default BM, ca, CA, or SMask in an ExtGState
  1603. %    - Image XObject with SMask
  1604. % Note: we deliberately don't check to see whether a Group is defined,
  1605. % because Adobe Illustrator 10 (and possibly other applications) define
  1606. % a page-level group whether transparency is actually used or not.
  1607. % Ignoring the presence of Group is justified because, in the absence
  1608. % of any other transparency features, they have no effect.
  1609. /pageusestransparency {        % <pagedict> pageusestransparency <bool>
  1610.   PDFversion PDFtransparencyversion lt NOTRANSPARENCY or {
  1611.     pop //false
  1612.   } {
  1613.     dup //false exch {
  1614.       4 dict 1 index resourceusestransparency { pop not exit } if
  1615.       /Parent knownoget not { exit } if
  1616.     } loop
  1617.     % Also check for transparency in the annotation (if not in resources).
  1618.     { pop //true } { annotsusetransparency } ifelse
  1619.   } ifelse
  1620. } bind def
  1621.  
  1622. % Check if transparency is specified in an ExtGState dict
  1623. /extgstateusestransparency {    % <gstate dict> extgstateusestransparency <bool>
  1624.   //false exch        % Assume no transparency
  1625.   {            % establish loop context
  1626.     exch pop oforce
  1627.     dup /BM knownoget { dup /Normal ne exch /Compatible ne and
  1628.                         { pop not exit } if
  1629.                           } if
  1630.     dup /ca knownoget { 1 ne { pop not exit } if } if
  1631.     dup /CA knownoget { 1 ne { pop not exit } if } if
  1632.     dup /SMask knownoget { /None ne { pop not exit } if } if
  1633.     pop
  1634.   } forall
  1635. } bind def
  1636.  
  1637. % Check the Resources of a page or Form. Check for loops in the resource chain.
  1638. /resourceusestransparency {    % <dict> <dict> resourceusestransparency <bool>
  1639.   {    % Use loop to provide an exitable context.
  1640.     /Resources knownoget not { 0 dict } if
  1641.     2 copy .knownget {
  1642.       { % Some circular references may be missed because scanning stops
  1643.         % when the 1st transparency is found.
  1644.         (   **** File has circular references in resource dictionaries.\n)
  1645.         pdfformaterror
  1646.       } if
  1647.       pop //false exit
  1648.     } if
  1649.     2 copy //true put              % In the current chain.
  1650.     dup /ExtGState knownoget {
  1651.       extgstateusestransparency
  1652.       { pop //true exit } if
  1653.     } if
  1654.     dup /XObject knownoget {
  1655.       //false exch {
  1656.     exch pop oforce dup /Subtype get
  1657.     dup /Image eq { 1 index /SMask known { pop pop not exit } if } if
  1658.     /Form eq {
  1659.       3 index exch resourceusestransparency { not exit } if
  1660.     } {
  1661.       pop
  1662.     } ifelse
  1663.       } forall { pop //true exit } if
  1664.     } if
  1665.     2 copy //false put             % Visited but not in the current chain.
  1666.     pop //false exit
  1667.   } loop
  1668.   exch pop
  1669. } bind def
  1670.  
  1671. % Check if the annotations on a page use transparency
  1672. /annotsusetransparency {    % <page dict> annotsusetransparency <bool>
  1673.    //false exch            % Assume no transparency
  1674.    /Annots knownoget {        % Get Annots array
  1675.      {
  1676.        oforce
  1677.        dup //null ne {
  1678.          /AP knownoget {    % Get appearance dict for the annoation
  1679.            /N knownogetdict {     % Get the /N (i.e. normal) appearance stream
  1680.              4 dict exch resourceusestransparency { pop //true exit } if
  1681.            } if
  1682.          } if              % If AP dict known
  1683.        } {
  1684.          pop
  1685.        } ifelse
  1686.      } forall            % For all annots on the page
  1687.    } if
  1688. } bind def
  1689.  
  1690. % Add a color name to our spot color list.  Ignore /All and /None
  1691. /putspotcolor {            % <name> <spotcolordict> putspotcolor -
  1692.   % The 'name' could be a string.  If so then convert to a name.
  1693.   exch dup type /stringtype eq { cvn } if
  1694.   dup dup /None eq exch /All eq or { pop pop } { 0 put } ifelse
  1695. } bind def
  1696.  
  1697. % Determine which spot colors are used within a color space  Note: This
  1698. % dict will include all colors used in Separation or DeviceN color spaces.
  1699. % Thus it may include Cyan, Magenta, Yellow, and Black.
  1700. %    <colorspace> <spotcolordict> colorspacespotcolors -
  1701. /colorspacespotcolors {
  1702.   exch dup type /arraytype eq {
  1703.     % If we have an Indexed color space then get the base space.
  1704.     dup 0 oget dup /Indexed eq {
  1705.       pop 1 oget 2 copy colorspacespotcolors
  1706.     } {
  1707.       % Stack:  <spotcolordict> <colorspace> <colorspacetype>
  1708.       dup /Separation eq exch /DeviceN eq or {
  1709.         dup 1 oget dup type /arraytype eq { 
  1710.       { oforce 2 index putspotcolor } forall
  1711.         } {
  1712.           2 index putspotcolor
  1713.         } ifelse
  1714.       } if
  1715.     } ifelse
  1716.   } if
  1717.   pop pop
  1718. } bind def
  1719.  
  1720. % Check the Resources of a page, form, or annotation.  Determine which spot
  1721. % colors are used within the resource  Note: The spot color dict will include
  1722. % all colors used in Separation or DeviceN color spaces.  Thus it may include
  1723. % Cyan, Magenta, Yellow, and Black.  We also pass a dict that is used to check
  1724. % for loops in the resource list.
  1725. %    <spotcolordict> <loopdict> <page/form/annot dict>
  1726. %          resourcespotcolors <spotcolordict> <loopdict>
  1727. /resourcespotcolors {
  1728.   {    % Use loop to provide an exitable context.
  1729.     % Exit if no Resources entry
  1730.     /Resources knownoget not { exit } if
  1731.     % Exit if we have already seen this dict
  1732.     2 copy known { pop exit } if
  1733.  
  1734.     % Save the Resources dict into our loop checking dict.
  1735.     2 copy 0 put
  1736.  
  1737.     % Scan resources that might contain a color space.
  1738.     dup /ColorSpace knownoget {
  1739.       { exch pop oforce 3 index colorspacespotcolors } forall
  1740.     } if
  1741.     dup /Pattern knownoget {
  1742.       { exch pop oforce 4 copy exch pop resourcespotcolors pop pop pop } forall
  1743.     } if
  1744.     dup /Shading knownoget {
  1745.       { exch pop oforce /ColorSpace oget 3 index colorspacespotcolors } forall
  1746.     } if
  1747.     /XObject knownoget {
  1748.       { exch pop oforce dup
  1749.         /Subtype get /Form eq { resourcespotcolors } { pop } ifelse
  1750.       } forall
  1751.     } if
  1752.     exit
  1753.   } loop
  1754. } bind def
  1755.  
  1756. % Determine which spot colors are used within the annotations.  Note: This
  1757. % dict will include all colors used in Separation or DeviceN color spaces.
  1758. % Thus it may include Cyan, Magenta, Yellow, and Black.
  1759. %    <spotcolordict> <loopdict> <annotsarray>
  1760. %          annotsspotcolors <spotcolordict> <loopdict>
  1761. /annotsspotcolors {
  1762.   { oforce
  1763.     dup //null ne {
  1764.       /AP knownoget {    % Get appearance dict for the annoation
  1765.         /N knownogetdict {        % Get the /N (i.e. normal) appearance stream
  1766.           resourcespotcolors
  1767.         } if            % If normal appearance streamknown
  1768.       } if            % If AP dict known
  1769.     } { 
  1770.       pop
  1771.     } ifelse
  1772.  } forall
  1773. } bind def
  1774.  
  1775. % Determine spot colors are used within a page.  We are creating a dict to
  1776. % hold the spot color names as keys.  Using a dict avoids having to worry
  1777. % about duplicate entries.  The keys in the dict contain the spot color
  1778. % names.  However the values have no meaning.  Note: This dict will include
  1779. % all colors used in Separation or DeviceN color spaces specified in the
  1780. % page's resources.  Thus it may include Cyan, Magenta, Yellow, and Black.
  1781. % There is no attempt to verify that these color spaces are actually used
  1782. % within the object streams for the page.
  1783. /pagespotcolors {        % <pagedict> pagespotcolors <spotcolordict>
  1784.   dup
  1785.   % Create a dict to hold spot color names.
  1786.   0 dict exch
  1787.   % Create a dict to be used to check for reference loops.
  1788.   4 dict exch 
  1789.   % Check for color spaces in the Resources
  1790.   resourcespotcolors
  1791.   % Also check for color spaces in the annotations.
  1792.   3 -1 roll
  1793.   /Annots knownoget { annotsspotcolors } if
  1794.   pop                % Discard reference loop dict
  1795. } bind def
  1796.  
  1797. % Determine how many (if any) spot colors are used by a page.
  1798. % Note:  This count does not include Cyan, Magenta, Yellow, or Black
  1799. /countspotcolors {        % <pagedict> countspotcolors <count>
  1800.   pagespotcolors        % Get dict with all spot colors
  1801.   dup length            % spot color dict length
  1802.   % Remove CMYK from the spot color count.
  1803.   [ /Cyan /Magenta /Yellow /Black ]
  1804.   { 2 index exch known { 1 sub } if } forall
  1805.   exch pop            % Remove spot color dict
  1806. } bind def
  1807.  
  1808. % ------ ColorSpace substitution support ------ %
  1809.  
  1810. %
  1811. %  <pagedict>   pdfshowpage_setcspacesub   <pagedict>
  1812. %
  1813. % Set up color space substitution for a page. Invocations of this procedure
  1814. % must be bracketed by the save/restore operation for the page, to avoid
  1815. % unintended effects on other pages.
  1816. %
  1817. % If any color space substitution is used, and the current color space is a
  1818. % device dependent color space, make sure the current color space is updated.
  1819. % There is an optimization in the setcolorspace pseudo-operator that does
  1820. % nothing if both the current and operand color spaces are the same. For
  1821. % PostScript this optimization is disabled if the UseCIEColor page device
  1822. % parameter is true. This is not the case for PDF, as performance suffers
  1823. % significantly on some PDF files if color spaces are set repeatedly. Hence,
  1824. % if color space substitution is to be used, and the current color space
  1825. % is a device dependent color space, we must make sure to "transition" the
  1826. % current color space.
  1827. %
  1828. /pdfshowpage_setcspacesub
  1829.   {
  1830.     false
  1831.       { /DefaultGray /DefaultRGB /DefaultCMYK }
  1832.       {
  1833.         dup 3 index /ColorSpace //rget exec
  1834.           { resolvecolorspace /ColorSpace defineresource pop }
  1835.           { pop }
  1836.         ifelse
  1837.       }
  1838.     forall
  1839.  
  1840.     % if using color space substitution, "transition" the current color space
  1841.       {
  1842.         currentcolorspace dup length 1 eq   % always an array
  1843.           {
  1844.             0 get
  1845.             dup /DeviceGray eq 1 index /DeviceRGB eq or 1 index /DeviceCMYK or
  1846.               { /Pattern setcolorspace setcolorspace }
  1847.               { pop }
  1848.             ifelse
  1849.           }
  1850.           { pop }
  1851.         if
  1852.       }
  1853.     if
  1854.   }
  1855. bind def
  1856.  
  1857. % Write OutputIntents to device if the device handles it
  1858. /writeoutputintents {
  1859.   currentdevice 1 dict dup /OutputIntent //null put readonly
  1860.   .getdeviceparams
  1861.   mark ne { pop pop
  1862.     % device supports OutputIntent parameter
  1863.     Trailer /Root oget /OutputIntents knownoget {
  1864.       dup type /arraytype eq {
  1865.         {    % process all output profiles present
  1866.           oforce
  1867.           dup length dict .copydict
  1868.       dup /DestOutputProfile knownoget {
  1869.           PDFfile fileposition exch
  1870.         mark exch { oforce } forall .dicttomark
  1871.         //true resolvestream
  1872.         [ { counttomark 1 add index
  1873.             64000 string readstring
  1874.             not { exit } if
  1875.           } loop
  1876.         ] exch closefile
  1877.         0 1 index { length add } forall .bytestring
  1878.         0 3 2 roll {
  1879.           3 copy putinterval
  1880.           length add
  1881.         } forall pop
  1882.         exch PDFfile exch setfileposition
  1883.         1 index /DestOutputProfile 3 2 roll put
  1884.       } if
  1885.       % Convert to string array because it's easier for the device
  1886.       [ 1 index /OutputCondition knownoget not { () } if
  1887.         2 index /OutputConditionIdentifier knownoget not { () } if
  1888.         3 index /RegistryName knownoget not { () } if
  1889.         4 index /Info knownoget not { () } if
  1890.         5 index /DestOutputProfile knownoget not { () } if
  1891.       ]
  1892.       [ /OutputIntent 3 2 roll .pdfputparams pop pop
  1893.           pop      % done with this OutputIntent dictionary
  1894.         } forall
  1895.       } {
  1896.         pop
  1897.         (   **** Warning: OutputIntent attribute of a wrong type is ignored.\n)
  1898.         pdfformaterror
  1899.       } ifelse
  1900.     } if    % OutputIntents known
  1901.     % tell device there are no more OutputIntents
  1902.     [ /OutputIntent [ ] .pdfputparams pop pop
  1903.   } if
  1904. } bind def
  1905.  
  1906. end            % pdfdict
  1907. .setglobal
  1908.