summaryrefslogtreecommitdiff
path: root/Master/tlpkg/tlgs/Resource/Init/pdf_main.ps
diff options
context:
space:
mode:
Diffstat (limited to 'Master/tlpkg/tlgs/Resource/Init/pdf_main.ps')
-rw-r--r--Master/tlpkg/tlgs/Resource/Init/pdf_main.ps3112
1 files changed, 3112 insertions, 0 deletions
diff --git a/Master/tlpkg/tlgs/Resource/Init/pdf_main.ps b/Master/tlpkg/tlgs/Resource/Init/pdf_main.ps
new file mode 100644
index 00000000000..85b5848e160
--- /dev/null
+++ b/Master/tlpkg/tlgs/Resource/Init/pdf_main.ps
@@ -0,0 +1,3112 @@
+% Copyright (C) 2001-2012 Artifex Software, Inc.
+% All Rights Reserved.
+%
+% This software is provided AS-IS with no warranty, either express or
+% implied.
+%
+% This software is distributed under license and may not be copied,
+% modified or distributed except as expressly authorized under the terms
+% of the license contained in the file LICENSE in this distribution.
+%
+% Refer to licensing information at http://www.artifex.com or contact
+% Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
+% CA 94903, U.S.A., +1(415)492-9861, for further information.
+%
+
+% pdf_main.ps
+% PDF file- and page-level operations.
+
+/.setlanguagelevel where { pop 2 .setlanguagelevel } if
+.currentglobal //true .setglobal
+/pdfdict where { pop } { /pdfdict 100 dict def } ifelse
+pdfdict begin
+
+% Patch in an obsolete variable used by some third-party software.
+/#? //false def
+
+% Test whether the current output device handles pdfmark.
+/.writepdfmarkdict 1 dict dup /pdfmark //null put readonly def
+/.writepdfmarks { % - .writepdfmarks <bool>
+ currentdevice //.writepdfmarkdict .getdeviceparams
+ mark eq { //false } { pop pop //true } ifelse
+ systemdict /DOPDFMARKS known or
+} bind def
+
+% For simplicity, we use a single interpretation dictionary for all
+% PDF graphics execution, even though this is too liberal.
+/pdfopdict mark
+ objopdict { } forall
+ drawopdict { } forall
+ /endstream { exit } bind
+ (%%EOF) cvn { exit } bind % for filters
+ /obj { ( **** Error: Content stream is not terminated by 'endstream'.\n)
+ pdfformaterror
+ ( Output may be incorrect.\n) pdfformaterror
+ } bind
+ % PDF 1.1 operators
+ /BX { /BXlevel BXlevel 1 add store } bind
+ /EX { /BXlevel BXlevel 1 sub store } bind
+ /PS { cvx exec } bind
+ % PDF 1.2 operators
+ /BMC {
+ /BMClevel BMClevel 1 add store
+ pop
+ } bind
+ /BDC {
+ /BMClevel BMClevel 1 add store
+ exch /OC eq {
+ dup type /nametype eq {
+ PDFfile fileposition exch % pos /Name
+ Page /Properties rget {
+ ocg-is-visible not {
+ OFFlevels BMClevel dup put
+ } if
+ } if
+ PDFfile exch setfileposition
+ } {
+ pop
+ } ifelse
+ } {
+ pop
+ } ifelse
+ } bind
+ /EMC {
+ OFFlevels BMClevel
+ 2 copy known {
+ 2 copy undef
+ } if
+ 1 sub /BMClevel exch store
+ pop
+ } bind
+ /MP { pop } bind
+ /DP { pop pop } bind
+ /- { 0 % Bug 690016
+ ( **** Error: Invalid operator '-' is assumed to be the number 0.\n)
+ pdfformaterror
+ ( Output may be incorrect.\n) pdfformaterror
+ } bind
+.dicttomark readonly def
+
+% ======================== Main program ======================== %
+
+end % pdfdict
+userdict begin
+
+/defaultfontname /Times-Roman def
+
+% Make sure the registered encodings are loaded, so we don't run the risk
+% that some of the indices for their names will overflow the packed
+% representation. (Yes, this is a hack.)
+SymbolEncoding pop
+DingbatsEncoding pop
+
+% Redefine 'run' so it recognizes PDF files.
+systemdict begin
+/.runps /run load def
+/run {
+ dup type /filetype ne { (r) file } if
+ % skip leading whitespace characters (actually anything less than or equal to <sp>)
+ { dup ( ) .peekstring not { //false exit } if
+ dup 0 get 32 le { pop dup read pop pop } { //true exit } ifelse
+ } loop
+ exch pop
+ {
+ % Appletalk PAP sends short strings with %! header expecting a response.
+ % 'gv' swallows the %!PS line, then sends DSC comments beginning with %%
+ % and also waits for a response. The following avoids those hangs.
+ dup 2 string .peekstring pop dup (%!) eq exch (%%) eq or {
+ cvx .runps
+ } {
+ dup 1023 string .peekstring pop
+ % "1024 string" exceeds current %stdin buffer
+ % Valid PDF file cannot be smaller than 400 bytes.
+ (%PDF-) search {
+ 3 1 roll pop pop
+ dup (%!PS) search not {
+ length 0 ne {
+ 1 index exch readstring pop pop
+ (%stderr) (w) file dup
+ ( **** Warning: File has some garbage before %PDF- .\n)
+ writestring flushfile
+ } {
+ pop
+ } ifelse
+ dup (%stdin) (r) file eq {
+ % Copy PDF from stdin to temporary file then run it.
+ //null (w+) /.tempfile .systemvar exec exch 3 1 roll
+ % stack: tempname stdin tempfile
+ 64000 string
+ {
+ % stack: tempname stdin tempfile string
+ 2 index 1 index readstring
+ exch 3 index exch writestring
+ not { exit } if
+ }
+ loop
+ pop exch closefile
+ % stack: tempname tempfile
+ dup 0 setfileposition
+ dup
+ runpdf
+ closefile deletefile
+ } {
+ runpdf
+ } ifelse
+ } {
+ pop pop pop pop cvx .runps % (%!PS) found first
+ } ifelse
+ } {
+ pop cvx .runps % (%PDF-) not found
+ } ifelse
+ } ifelse
+ } {
+ closefile % file was empty
+ } ifelse
+} bind odef
+currentdict /runpdfstring .undef
+
+/runpdfbegin { % <file> runpdfbegin -
+ userdict begin
+ % It turns out that the PDF interpreter uses memory more
+ % effectively if it is run under at least one level of save.
+ % This is counter-intuitive, and we don't understand why it happens,
+ % but the improvement is significant.
+ /PDFTopSave save def
+ <</ProcessDSCComment //null>> setuserparams
+ <</ProcessComment //null>> setuserparams
+ %% Bug #696487, allow dict stack to grow without limit, as these PDF
+ %% files have stupidly deep gsave nesting and we need a dictionary per gsave
+ %% at the moment.
+ %% Remove ths if bug #696511 is ever completed (move ExtGstate parameters into gstate)
+ <</MaxDictStack -1>> setuserparams
+ %% Bug #696567, same customer as above. Ths time they have a file with a page whch has
+ %% 447000 ExtGState references (all of hwch contain no gstate!) Because we allocate
+ %% these on the stack, allow the stack to grow indefinitely in order to accomodate
+ %% such stupid files. Also move these lines from the end of the routine, so that
+ %% the increases are in place before we call odfopen, which will build the
+ %% resources and needs this definition in place.
+ <</MaxOpStack -1>> setuserparams
+
+ 0 setobjectformat
+ /Page# //null def
+ /Page //null def
+ /DSCPageCount 0 def
+ /PDFSave //null def
+ GS_PDF_ProcSet begin
+ pdfdict begin
+ pdfopen begin
+ /CumulativePageCount currentpagedevice /PageCount get def
+} bind def
+
+/runpdfpagerange { % - runpdfpagerange <firstpage#> <lastpage#>
+<</DisablePageHandler true>> setpagedevice
+ /PortfolioPage where {
+ pop
+ PortfolioPage cvi dup pdfpagecount add % a b+1
+ /PortfolioPage dup load % a b+1 /P ()
+ ( ) 1 index copy pop
+ dup 3 index exch cvs pop % a b+1 /P (b+1)
+ store
+ 1 sub % a b
+ /FirstPage where { pop FirstPage <</DisablePageHandler true>> setpagedevice} { 1 } ifelse
+ /LastPage where { pop LastPage <</DisablePageHandler true>> setpagedevice} {2000000000} ifelse % a b fp lp
+ 2 index 2 index lt { % b < fp
+ 1e10
+ } {
+ 3 index 2 index gt { % a > fp
+ 1
+ } {
+ 1 index 4 index sub 1 add
+ } ifelse
+ } ifelse % a b fp lp f
+ 3 index 2 index lt { % b < bp
+ 3 index 5 index sub 1 add % b-a+1=count
+ } {
+ 4 index 2 index gt {
+ 0
+ } {
+ 1 index 5 index sub 1 add
+ } ifelse
+ } ifelse % a b fp lp f l
+ 6 2 roll pop pop pop pop
+
+ QUIET not {
+ 1 index 1 index gt {
+ (Skipping the subfile.) = flush
+ } {
+ (Processing pages ) print 1 index =only ( through ) print dup =only
+ (.) = flush
+ } ifelse
+ } if
+ } {
+ /PageList where {
+ pop PageList
+ (even) anchorsearch {
+ pop length 0 gt {
+ /runpdfpagerange /syntaxerror cvx signalerror
+ } if
+ /PDFPageList pdfpagecount 1 add array def
+ 2 2 pdfpagecount {
+ PDFPageList exch 1 put
+ } for
+ 1 pdfpagecount
+ QUIET not {
+ (Processing even-numbered pages\n) print
+ (.) = flush
+ } if
+ } {
+ (odd) anchorsearch {
+ pop length 0 gt {
+ /runpdfpagerange /syntaxerror cvx signalerror
+ } if
+ /PDFPageList pdfpagecount 1 add array def
+ 1 2 pdfpagecount {
+ PDFPageList exch 1 put
+ } for
+ 1 pdfpagecount
+ QUIET not {
+ (Processing odd-numbered pages\n) print 1 index =only ( through ) print dup =only
+ (.) = flush
+ } if
+ } {
+ %% validate string contents, check for digit comma or minus
+ dup
+ {
+ dup 44 eq not {
+ dup 45 eq not {
+ dup 48 lt 1 index 57 gt or {
+ /runpdfpagerange /syntaxerror cvx signalerror
+ } if
+ } if
+ } if
+ pop
+ }
+ forall
+ <</DisablePageHandler true>> setpagedevice
+ /PDFPageList pdfpagecount 1 add array def
+ {
+ (,) search {
+ %% We now have (post) (,) (pre)
+ exch pop %% get rid of the (,), leave the (post) as the string for the next iteration, deal with the section up to the comma
+ (-) search {
+ %% Now we have (end) (-) (start)
+ exch pop %% get rid of the minus (end) (start)
+ 0 exch {48 sub exch 10 mul add} forall
+ %% Make sure the start of the range is inside the number of available pages
+ dup pdfpagecount le {
+ exch
+ %% deal with a trailing '-' by replacing it with the number of pages in the file
+ dup length 0 eq {
+ pop pdfpagecount
+ }{
+ 0 exch {48 sub exch 10 mul add} forall
+ } ifelse
+ 1 exch %% start 1 end
+ %% Make sure the end of the range is inside the number of available pages
+ dup pdfpagecount gt {pop pdfpagecount} if
+ {PDFPageList exch 1 put} for
+ } {
+ %% start of range invalid, drop this range.
+ pop pop
+ }ifelse
+ }{
+ %% no minus signs, must be a simple page number
+ 0 exch {48 sub exch 10 mul add} forall
+ %% ensure its in the valid range of pages
+ dup pdfpagecount le {
+ PDFPageList exch 1 put
+ } {
+ pop
+ } ifelse
+ } ifelse
+ }{
+ %% no commas separating pages, just the original string (), deal with its as a section, then exit the loop
+ (-) search {
+ %% Now we have (end) (-) (start)
+ exch pop %% get rid of the minus (end) (start)
+ 0 exch {48 sub exch 10 mul add} forall
+ %% Make sure the start of the range is inside the number of available pages
+ dup pdfpagecount le {
+ exch
+ %% deal with a trailing '-' by replacing it with the number of pages in the file
+ dup length 0 eq {
+ pop pdfpagecount
+ }{
+ 0 exch {48 sub exch 10 mul add} forall
+ } ifelse
+ 1 exch %% start 1 end
+ %% Make sure the end of the range is inside the number of available pages
+ dup pdfpagecount gt {pop pdfpagecount} if
+ {PDFPageList exch 1 put} for
+ } {
+ %% start of range invalid, drop this range.
+ pop pop
+ }ifelse
+ }{
+ %% no minus signs, must be a simple page number
+ 0 exch {48 sub exch 10 mul add} forall
+ %% ensure its in the valid range of pages
+ dup pdfpagecount le {
+ PDFPageList exch 1 put
+ } {
+ pop
+ } ifelse
+ } ifelse
+ exit %% done all the sections.
+ } ifelse
+ } loop
+ QUIET not {
+ (Processing pages ) print PageList =only
+ (.) = flush
+ } if
+ } ifelse
+ } ifelse
+ 1 pdfpagecount
+ }{
+ /FirstPage where {
+ <</DisablePageHandler true>> setpagedevice
+ pop FirstPage dup pdfpagecount gt {
+ (\nRequested FirstPage is greater than the number of pages in the file: ) print
+ pdfpagecount = flush
+ } if
+ } {
+ 1
+ } ifelse
+ /LastPage where {<</DisablePageHandler true>> setpagedevice pop LastPage pdfpagecount .min } { pdfpagecount } ifelse
+ 1 index 1 index gt {
+ ( No pages will be processed \(FirstPage > LastPage\).) = flush
+ } {
+ QUIET not {
+ (Processing pages ) print 1 index =only ( through ) print dup =only
+ (.) = flush
+ } if
+ } ifelse
+ } ifelse
+ }ifelse
+} bind def
+
+/dopdfpages { % firstpage# lastpage# dopdfpages -
+ << /PDFScanRules //true >> setuserparams % set scanning rules for PDF vs. PS
+ << /RenderTTNotdef systemdict
+ /RENDERTTNOTDEF get >> setuserparams % Should we render TT /.notdef
+ 1 exch
+ {
+ %% If we have a array of pages to render, use it.
+ /PDFPageList where {
+ pop dup PDFPageList exch get 1 eq
+ }
+ {true} ifelse
+
+ {
+ dup /Page# exch store
+ QUIET not { (Page ) print dup //== exec flush } if
+ pdfgetpage pdfshowpage
+ }{
+ pop
+ }ifelse
+ } for
+ % Indicate that the number of spot colors is unknown in case the next page
+ % imaged is a PS file.
+ currentpagedevice /PageSpotColors known { << /PageSpotColors -1 >> setpagedevice } if
+ << /PDFScanRules //null >> setuserparams % restore scanning rules for PS
+} bind def
+
+/runpdfend {
+ RepairedAnError
+ {
+ printrepairederror
+ } {
+ Repaired { printrepaired } if
+ } ifelse
+ currentdict pdfclose
+ end % temporary dict
+ end % pdfdict
+ end % GS_PDF_ProcSet
+ PDFTopSave restore
+ end % userdict
+ 2 vmreclaim % couldn't hurt
+} bind def
+
+% Copy stream to an external temporary file and
+% return the file name as PS name.
+/copy_embedded_file {
+ //true resolvestream % strm
+ dup 1023 string .peekstring pop % "1024 string" exceeds current %stdin buffer
+ dup length 400 ge { % Valid PDF file cannot be smaller than 400 bytes.
+ (%PDF-) search {
+ pop pop pop //true
+ } {
+ pop //false
+ } ifelse
+ } {
+ pop //false
+ } ifelse {
+ //null (w) /.tempfile % strm (name) null (w) /.tempfile
+ .systemvar exec % strm (name) file
+ 3 -1 roll % (name) file strm
+ 32768 string % (name) file strm (buf)
+ { 3 copy readstring % (name) file strm (buf) file (data) bool
+ 3 1 roll % (name) file strm (buf) bool file (data)
+ writestring % (name) file strm (buf) bool
+ not { exit } if
+ } loop
+ pop closefile % (name) file
+ closefile % (name)
+ cvn % /name
+ } {
+ closefile
+ } ifelse
+} bind def
+
+% Recursively enumerate /Names entries
+% <node> pdf_collection_names /temp_file_name ...
+/pdf_collection_names {
+ dup /Names knownoget {
+ exch pop
+ { oforce
+ dup type /dicttype eq {
+ /EF knownoget {
+ /F knownoget {
+ copy_embedded_file
+ } if
+ } if
+ } {
+ pop
+ } ifelse
+ } forall
+ } {
+ /Kids knownoget {
+ { oforce
+ dup //null ne {
+ pdf_collection_names
+ } {
+ pop
+ } ifelse
+ } forall
+ } if
+ } ifelse
+} bind def
+
+% Copy selected subfiles to temporary files and return the file names
+% as a PostScript names to protect them from restore.
+% Currently, all PDF files in the Portfolio are extracted and returned.
+%
+% - pdf_collection_files [ /temp_file_name ... /temp_file_name
+/pdf_collection_files {
+ mark
+ Trailer /Root knownoget {
+ dup /Collection oknown {
+ /Names knownoget {
+ /EmbeddedFiles knownoget {
+ pdf_collection_names
+ } if
+ } if
+ } {
+ pop
+ } ifelse
+ } if
+} bind def
+
+/runpdf { % <file> runpdf -
+ %% Get the PDF filename (it *must* be a file even if it came from stdin it gets
+ %% copied to a temporary file) and store it in pdfdict. We will use this for
+ %% hashing fonts to detect if fonts with the same name are from different files.
+ %%
+ dup currentglobal exch true setglobal .getfilename exch setglobal /InputPDFFileName exch pdfdict 3 1 roll .forceput
+
+ //runpdfbegin exec
+ //pdf_collection_files exec
+ dup mark eq {
+ pop
+ process_trailer_attrs
+ //runpdfpagerange exec
+ //dopdfpages exec
+ //runpdfend exec
+ } {
+ //runpdfend exec
+ ]
+ (1 ) 10 string copy exch
+ {
+ dup type /filetype eq {
+ //runpdfbegin exec
+ dup /PortfolioPage exch def
+ process_trailer_attrs
+ //runpdfpagerange exec
+ //dopdfpages exec
+ //runpdfend exec
+ closefile
+ } {
+ .namestring dup (r) file
+ //runpdfbegin exec
+ /PortfolioPage 2 index def
+ process_trailer_attrs
+ //runpdfpagerange exec
+ //dopdfpages exec
+ //runpdfend exec
+ deletefile
+ } ifelse
+ } forall
+ pop
+ } ifelse
+} bind def
+
+currentdict /pdf_collection_files .undef
+
+end % systemdict
+% Redefine the procedure that the C code uses for running piped input.
+% It is OK to use { (%stdin) run } here, because a startjob cannot occur.
+/.runstdin {
+ { (%stdin) run } execute0
+} bind def
+
+end % userdict
+pdfdict begin
+
+% ======================== File parsing ======================== %
+
+% Read the cross-reference and trailer sections.
+
+% I believe the definitions here are only used when parsing the trailer
+% dictionary and cross-reference table. So, following on from bug 697351
+% we will validate the operands to /R here, because the trailer and xref
+% are comparatively small. Note that the bug does not expose a problem
+% here, but we probably ought to validate the operands. Of course, if
+% they are invalid, the PDF file is probably unreadable anyway.
+
+/traileropdict mark
+ (<<) cvn { /dictlevelcount dictlevelcount 1 add store mark } bind
+ (>>) cvn { { .dicttomark } stopped {
+ ( **** Warning: File has unbalanced >> in trailer.\n) pdfformatwarning
+ } if
+ /dictlevelcount dictlevelcount 1 sub def
+ dictlevelcount 0 eq { exit } if
+ } bind
+ ([) cvn { mark } bind % ditto
+ (]) cvn dup load
+% /true true % see .pdfexectoken in pdf_base.ps
+% /false false % ibid.
+% /null null % ibid.
+ /R {
+ 1 index type /integertype eq 1 index type /integertype eq and {
+ /resolveR cvx 3 packedarray cvx
+ } {
+ ( **** Error: indirect object reference \(R\) encountered with invalid arguments.) pdfformaterror
+ ( Output may be incorrect.\n) pdfformaterror
+ } ifelse
+ } bind % see Objects below
+.dicttomark readonly def
+
+% After reading entry count: skip whitespace, exit on a digit
+% (presumably the object offset, otherwise throw /syntaxerror
+/xref-char-dict <<
+ 0 {} % \000
+ 9 1 index % \t
+ 10 1 index % \r
+ 12 1 index % \f
+ 13 1 index % \n
+ 32 1 index % ' '
+
+ 48 { exit } bind % '0'
+ 49 1 index % '1'
+ 50 1 index % '2'
+ 51 1 index % '3'
+ 52 1 index % '4'
+ 53 1 index % '5'
+ 54 1 index % '6'
+ 55 1 index % '7'
+ 56 1 index % '8'
+ 57 1 index % '9'
+ 116 { % 't'railer
+ PDFfile 7 string .peekstring not { () } if
+ dup /trailer eq {
+ % Empty xref section
+ pop exit
+ } {
+ ( **** Warning: Invalid string \() exch concatstrings
+ (\) follows xref section header.\n) concatstrings
+ pdfformatwarning
+ /setxrefentry cvx /syntaxerror signalerror
+ } ifelse
+ } bind
+>> readonly def
+
+ % Read original version (pre PDF 1.5) of the xref table.
+ % Note: The position is the location of 'xref'. The current PDFfile
+ % position is just after the 'XREF'.
+/readorigxref % <pos> readorigxref <trailerdict>
+ {
+ pop % We do not need the position.
+
+ % First we search this (and any Previous) trailers, looking for
+ % the /Size of the xref. We use ths to initialise our storage
+ % of xref and similar objects. This avoids us havign to continually
+ % resize these objescts which is very wasteful, and leads to us
+ % spending much time in memory amanagement.
+ % Bug #696454
+ PDFfile fileposition
+ /dictlevelcount 0 def
+ /TrailerSizeError false def
+ /ICCProfileNError false def
+ /TrailerSize 0 def
+
+ {
+ % Throw away the 'xref' data up to the trailer dictionary
+ PDFfile 0 (trailer) /SubFileDecode filter flushfile
+ % Now read the trailer dictionary
+ PDFfile traileropdict .pdfrun
+
+ dup /Size known {
+ % If we have a /Size then use it and exit this loop
+ /Size get /TrailerSize exch def
+ exit
+ }{
+ dup /Prev known {
+ % We don't have a Size, but we have a Previous, set up to read it.
+ /Prev get PDFfile exch setfileposition
+ }{
+ % No size and no Prev with a Size. Fall back to resizing the xref as we go.
+ pop
+ (*** Warning: No trailer dictionary with a Size detected, xref processing will be dynamic and slower) pdfformatwarning
+ /TrailerDict 0 def
+ exit
+ } ifelse
+ }ifelse
+ }loop
+
+ % Initialise the objects with the detected Size.
+ TrailerSize growPDFobjects
+ PDFfile exch setfileposition
+ 0 % Initialize xref table error counter
+ false % Have we seen at least one section entry in this xref ? Bug #694342
+ { PDFfile token pop % first object # or trailer
+ dup /trailer eq {
+ %% check to see if we have seen at least an empty section for this xref
+ pop {exit}
+ {
+ %% we have not seen any section entries in an xref, not even an empty section (xref 0 0)
+ %% Bug 694342, treat this as an error and rebuild the xref.
+ /setxrefentry cvx /syntaxerror signalerror
+ } ifelse
+ }
+ {
+ %% remove the boolean telling us if we have a section or not, leaving the first object number
+ exch pop
+ } ifelse
+ PDFfile token pop % entry count
+
+ % remaining must be whitespace only (otherwise this xref Size was invalid.
+ { PDFfile (0) .peekstring not { pop exit } if
+ 0 get //xref-char-dict exch .knownget {
+ exec
+ } {
+ ( **** Warning: xref subsection header has extra characters.\n)
+ pdfformatwarning
+ /setxrefentry cvx /syntaxerror signalerror
+ } ifelse
+ PDFfile read { pop } { exit } ifelse
+ } loop
+ % This section might be adding new objects:
+ % ensure that Objects and Generations are big enough.
+ % stack: <err count> <first obj> <entry count>
+ 2 copy add
+ TrailerSize gt {
+ TrailerSizeError not {
+ /TrailerSizeError true def
+ PDFSTOPONERROR not {
+ (**** Warning: Discovered more enties in xref than declared in trailer /Size\n) pdfformatwarning
+ } {
+ /readorigxref cvx /rangecheckerror signalerror
+ } ifelse
+ } if
+ % We now know that the /Size was wrong. We could read the whole table
+ % resizing on every section, but if there are a lot of sections we
+ % end up spending lots of time in memory management (Bug #696454) so
+ % instead add 64k to the first object number in the section. This will
+ % waste some memory, but is faster in ths case.
+ 1 index 65534 add dup /TrailerSize exch def
+ growPDFobjects
+ } if
+ { % stack: <err count> <obj num>
+ % Read xref line
+ PDFfile 20 string readstring pop % always read 20 chars.
+ token pop % object position
+ exch token pop % generation #
+ exch token pop % n or f
+ exch % stack: <err count> <obj#> <loc> <gen#> <tag> <remainder of line>
+ % check to make sure trailing garbage is just white space
+ //false 1 index { 32 gt or } forall {
+ 6 -1 roll 1 add 6 1 roll % bump error count on garbage
+ dup (\n) search {
+ exch pop exch pop
+ } {
+ (\r) search {
+ exch pop exch pop
+ } if
+ } ifelse
+ length
+ PDFfile fileposition exch sub PDFfile exch setfileposition
+ } if
+ pop % Stack: <err count> <obj#> <loc> <gen#> <tag>
+ dup /n eq { % xref line tag is /n
+ pop % pop dup of line tag
+ 1 index 0 eq {
+ ( **** Warning: considering '0000000000 XXXXX n' as a free entry.\n)
+ pdfformatwarning
+ } {
+ 0 3 1 roll % Set ObjectStream object number = 0
+ //false setxrefentry % Save xref entry, don't change existing entries
+ 3 -1 roll pop % Remove ObjectStream object onumber
+ } ifelse
+ }
+ { % xref line tag was not /n
+ /f ne % verify that the tag was /f
+ { /setxrefentry cvx /syntaxerror signalerror
+ } if
+ } ifelse
+ pop pop % pop <obj location> and <gen num>
+ % stack: <err count> <obj num>
+ 1 add % increment object number
+ } repeat
+ pop % pop <obj #>
+ true % We have seen at least one entry in an xref section Bug #694342
+ } loop
+ 0 ne {
+ ( **** Warning: length of some xref entries is not equal to 20 bytes.\n)
+ pdfformatwarning
+ } if
+ PDFfile traileropdict .pdfrun
+ } bind def
+
+currentdict /xref-char-dict undef
+
+ % This dicitonary is used to read the xref dictionary. It should work for
+ % reading any dictionary. dictlevelcount must contain 0.
+/xrefopdict mark
+ (<<) cvn { /dictlevelcount dictlevelcount 1 add def mark } bind
+ (>>) cvn { .dicttomark /dictlevelcount dictlevelcount 1 sub def
+ dictlevelcount 0 eq { exit} if } bind
+ ([) cvn { mark } bind % ditto
+ (]) cvn dup load
+% /true true % see .pdfexectoken in pdf_base.ps
+% /false false % ibid.
+% /null null % ibid.
+ /R { /resolveR cvx 3 packedarray cvx } bind % see Objects below
+.dicttomark readonly def
+
+% Get a variable length positive integer value from a stream. A value
+% of zero is returned if the count is zero.
+/getintn { % <stream> <count> getintn int
+ 0 exch { 256 mul 1 index read pop add } repeat
+ exch pop % Discard stream
+} bind def
+
+% This array contains handlers for processing the different types of
+% entries in the XRef stream.
+% Stack: <Xrefdict> <xref stream> <Index array> <pair loc> <obj num>
+% <field 2> <field 3>
+% The handlers leave the stack unchanged.
+/xref15entryhandlers [
+ { % XRef entry type 0 - free or f type xref entry
+% (free ) print
+% (obj num: ) print 2 index pdfstring cvs print ( ) print
+% (loc: ) print 1 index pdfstring cvs print ( ) print
+% (gen: ) print dup === flush
+ } bind % Do nothing for free xref entries
+ % XRef entry type 1 - normal or n type xref entry
+ { % field 2 = obj loc, field 3 = gen num
+% (normal ) print
+% (obj num: ) print 2 index pdfstring cvs print ( ) print
+% (loc: ) print 1 index pdfstring cvs print ( ) print
+% (gen: ) print dup === flush
+ 0 3 1 roll % set stream number = 0
+ //false setxrefentry
+ 3 -1 roll pop % remove stream number
+ } bind
+ % XRef entry type 2 - compressed object type xref entry
+ { % field 2 = object stream num, field 3 = index into object stream
+% (Compressed objects: ) print
+% (obj num: ) print 2 index pdfstring cvs print ( ) print
+% (field 2: ) print 1 index pdfstring cvs print ( ) print
+% (field 3: ) print dup === flush
+ 0 //false setxrefentry pop % set generation number = 0
+ } bind
+] def
+
+ % Read the PDF 1.5 version of the xref table.
+ % Note: The position is the location of the start of the dictionary object
+ % In PDF 1.5, the XRef dictionary also serves as the trailer dictionary
+/readpdf15xref % <pos> readpdf15xref <trailerdict>
+ {
+ /Classic-xref //false store
+ PDFfile exch setfileposition % move to start of object
+ % Get object number, revision, and 'obj' and discard
+ //false PDFfile token {
+ type /integertype eq {
+ PDFfile token {
+ type /integertype eq {
+ PDFfile token {
+ /obj eq or
+ } if
+ } if
+ } if
+ } if
+ } if
+ not {
+ /readpdf15xref cvx /syntaxerror signalerror
+ } if
+ % Get the XRef dicitionary
+ /dictlevelcount 0 def PDFfile xrefopdict .pdfrun
+ % Verify that we have an XRef dictionary
+ dup /Type get /XRef ne {
+ /readpdf15xref cvx /syntaxerror signalerror
+ } if
+ % Ensure that we we have room in the objects array, etc.
+ dup /Size get 1 index /Index .knownget {
+ %% if we have a /Index, remember to add the starting index on to the size
+ dup 0 get 3 -1 roll add exch
+ %% Get the staring index and number of entries from the Index array
+ %% add them, and see if the result is larger than the starting index plus
+ %% Size entry (yes they are *supposed* to be consistent.....)
+ %% Bug #696365
+ dup 0 get exch 1 get add 2 copy gt {
+ pop
+ }{
+ exch pop
+ } ifelse
+ } if
+ growPDFobjects
+ % Create a stream for the XRef data
+ PDFfile token pop pop % Skip over 'stream'
+ dup stream //false resolvestream
+ % Stack: <XRefdict> <xref stream>
+ % The Index array defines the ranges of object numbers in the
+ % XRef stream. Each value pair is consists of starting object
+ % number and the count of consecutive objects.
+ % Get the Index array, if present
+ 1 index /Index .knownget not { % If no Index array ...
+ [ 0 3 index /Size get ] % Default = [ 0 Size ]
+ } if
+ % Loop through the Index array
+ 0 2 2 index length 1 sub {
+ % Get start and end of object range
+ 2 copy get % Start of the range
+ dup 3 index 3 index 1 add get % Number of entries in range
+ % Loop through the range of object numbers
+ add 1 sub 1 exch { % Form end of range, set increment = 1
+ % Stack: <Xrefdict> <xref stream> <Index array> <pair loc> <obj num>
+ % Get xref parameters. Note: The number of bytes for each parameter
+ % is defined by the entries in the W array.
+ 4 index /W get aload pop % Get W array values
+ % The first field indicates type of entry. Get first field value.
+ % If the num. of bytes for field 1 is 0 then default field value is 1
+ 3 -1 roll dup 0 eq { pop 1 } { 6 index exch getintn } ifelse
+ % Get the handler for the xref entry type. We will execute the
+ % handler after we get the other two field values.
+ xref15entryhandlers exch get
+ 3 -1 roll 6 index exch getintn % Get second field
+ 3 -1 roll 6 index exch getintn % Get third field
+ 3 -1 roll exec % Execute Xref entry handler
+ pop pop pop % Remove field values and obj num
+ } for % Loop through Xref entries
+ pop % Remove Index array pair loc
+ } for % Loop through Index array entries
+ pop pop % Remove Index array and xref stream
+ } bind def
+
+% Read the cross-reference table.
+% <pos> is the position either from the startxref statement or the /Prev
+% entry in the prior trailer dictionary.
+/readxref % <pos> readxref <trailerdict>
+ {
+ PDFoffset add PDFfile exch
+ % Check that the given location is within the file.
+ dup PDFfilelen gt {
+ ( **** Warning: Specified xref location is beyond end of file.\n)
+ pdfformatwarning
+ /readxref cvx /invalidaccess signalerror
+ } if
+ setfileposition
+ % In some PDF files, this position actually points to
+ % white space before the xref line. Skip over this here.
+ {
+ PDFfile fileposition PDFfile read pop 32 gt { exit } if pop
+ } loop
+ dup % Make copy of the file position (before last char was read).
+ PDFfile exch setfileposition
+ % The PDF specification says that the 'xref' must be on a line
+ % by itself. The code here formerly used readline and linene to
+ % check this. However, Acrobat Reader only requires the line to
+ % begin with 'xref', and there are enough applications producing
+ % non-compliant PDF files that we have to do this too.
+ PDFfile pdfstring 0 4 getinterval readstring pop
+ (xref) eq
+ {
+ readorigxref % 'xref' -> original xref table
+ % if hybrid-reference PDF, also fetch the entries
+ % found in the XRef stream pointed by /XRefStm
+ dup /XRefStm knownoget {
+ %% Bug #695883 the test file has an XRefStm which points beyond the end of the file.
+ %% We check that here and simply fall back to thje classic xref if this error occurs.
+ dup PDFfilelen lt{
+ readpdf15xref pop
+ } {
+ ( **** Error: This hybrid file's XRefStm points beyond the end of file.\n Ignoring error, output may be incorrect.\n) pdfformaterror
+ pop
+ }ifelse
+ } if
+ }
+ { readpdf15xref } % otherwise assume PDF 1.5 xref stream
+ ifelse
+ } bind def
+
+% Open a PDF file and read the header, trailer, and cross-reference.
+/pdfopen { % <file> pdfopen <dict>
+ % Color space substitution in PDF is handled somewhat differently
+ % than in PostScript. A given device color space will be substituted
+ % if the corresponding "Default..." entry exists in the Page's
+ % Resource dictionary (which might be inhereted); there is no
+ % UseCIEColor to enable/disable color mapping.
+ %
+ % This behavior is achieved by always setting UseCIEColor to true
+ % in the page device dictionary. If the value of this parameter was
+ % originally false (i.e.: the output device does not perform color
+ % space substitution by default), the instances DefaultGray,
+ % DefaultRGB, and DefaultCMYK of the (local) ColorSpace category
+ % are redefined to be DeviceGray, DeviceRGB, and DeviceCMYK,
+ % respectively. This is not done if UseCIEColor is true by default,
+ % as in that case color substitution is presumably desired even
+ % if the file does not request it.
+ currentpagedevice /UseCIEColor .knownget dup { pop } if not
+ { .currentglobal //false .setglobal
+ /DefaultGray { /DeviceGray } cvlit /ColorSpace defineresource pop
+ /DefaultRGB { /DeviceRGB } cvlit /ColorSpace defineresource pop
+ /DefaultCMYK { /DeviceCMYK } cvlit /ColorSpace defineresource pop
+ .setglobal
+ }
+ if
+ pdfopenfile begin
+ pdfopencache
+ currentdict end
+} bind def
+
+/process_trailer_attrs { % - process_trailer_attrs -
+ writeoutputintents
+ .writepdfmarks {
+ % Copy bookmarks (outline) to the output.
+ Trailer /Root knownoget {
+ /Outlines knownoget {
+ /NO_PDFMARK_OUTLINES where {pop NO_PDFMARK_OUTLINES not}{true}ifelse
+ {
+ /First knownoget {
+ dup type /dicttype eq {
+ { dup writeoutline /Next knownoget not { exit } if
+ dup type /dicttype eq not {exit} if
+ } loop
+ }
+ {pop} ifelse
+ }if
+ } {
+ pop
+ }ifelse
+ } if
+ } if
+ count /pdfemptycount exch def
+ Trailer /Info {knownoget} stopped {
+ ( **** Error: Unable to read Info dictionary from Trailer, Info will not be preserved.\n) pdfformaterror
+ count pdfemptycount sub {pop} repeat
+ }
+ {
+ {
+ mark exch
+ { /Author /Creator /Title /Subject /Keywords
+ % /Producer is Ghostscript; /CreationDate is now; /ModDate is also now.
+ } {
+ 2 copy knownoget { 3 -1 roll } { pop } ifelse
+ } forall
+ pop
+ dup mark ne { {/DOCINFO pdfmark} stopped {cleartomark} if } { pop } ifelse
+ } if
+ } ifelse
+ } if
+ % Initialize OC groups
+ Trailer /Root knownoget {
+ /OCProperties knownoget {
+ % By default, OCGs are 'on'; mark only 'off' OCGs.
+ % If, contrary to the spec, BaseState is OFF, mark all OCGs
+ % and unmark ON ones. Bug 691491.
+ dup /OCGs knownoget not { {} } if exch
+ /D knownoget {
+ dup /BaseState knownoget { /OFF eq } { //false } ifelse {
+ ( **** Warning: Default viewing OC config dictionary has /BaseState /OFF\n)
+ pdfformatwarning
+ 1 index {
+ oforce dup type /dicttype eq {
+ /OFF 0 put
+ } {
+ pop
+ } ifelse
+ } forall
+ /ON knownoget {
+ { oforce dup type /dicttype eq {
+ /OFF undef
+ } {
+ pop
+ } ifelse
+ } forall
+ } if
+ } {
+ /OFF knownoget {
+ { oforce dup type /dicttype eq {
+ /OFF 0 put
+ } {
+ pop
+ } ifelse
+ } forall
+ } if
+ } ifelse
+ } if
+ pop
+ } if
+ } if
+
+ % Enumerate all AcroForm fields and link all separate widgets
+ % to the parent field.
+ Trailer /Root knownoget {
+ /AcroForm knownoget {
+ %% If we don't have a NeedAppearances entry, treat as if true.
+ %% We know Acrobat always regenerates all annotait
+ dup /NeedAppearances knownoget not { //true } if {
+ /NeedAppearances //true def
+ dup
+ /Fields knownoget {
+ { oforce
+ %% Make sure the entry from the Fields array is a dictionary
+ %% Bug #692447.pdf has an array of nulls.
+ dup type /dicttype eq {
+ link_widget_annots
+ }if
+ pop
+ } forall
+ } if
+ pop
+ } {
+ pop
+ } ifelse
+ } if
+ } if
+
+ % Use OutputIntent ICC profile
+ systemdict /UsePDFX3Profile .knownget {
+ dup //false eq {
+ pop
+ } {
+ dup //true eq { pop 0 } if
+ dup type /integertype eq {
+ Trailer /Root oget /OutputIntents knownoget {
+ dup length 2 index le % i [] bool
+ 2 index 0 lt or {
+ pop pop
+ (Source file has no OutputIntent with this number.\n)
+ } {
+ exch oget dup type /dicttype ne { pop << >> } if
+ /DestOutputProfile knownoget {
+ [ /ICCBased 3 -1 roll ] ICCBased-resolve
+ 1 get .set_outputintent
+ ()
+ } {
+ (This OutputputIntents dictionary has no profile.\n)
+ } ifelse
+ } ifelse
+ } {
+ pop (File has no /OutputIntents attribute\n)
+ } ifelse
+ } {
+ pop (UsePDFX3Profile must be a boolean or an integer.\n)
+ } ifelse
+ dup () eq {
+ pop
+ } {
+ ( **** ) stderrprint stderrprint
+ } ifelse
+ } ifelse
+ } if
+ Trailer /Root knownoget { /PageLabels knownoget {
+ %% Currenlty only the pdfwrite device can handle PageLabels
+ %% because we deal with these using putparams, not pdfmarks
+ %% This is because the pdfmark syntax can't handle all the
+ %% possible page label formats in a PDF file!
+ /WantsPageLabels /GetDeviceParam .special_op {
+ pop pop
+ .pdfpagelabels
+ } {
+ pop
+ } ifelse
+ } if
+ } if
+} bind def
+
+% Verify that each entry in the xref table is pointing at an object with
+% the correct object number and generation number.
+/verify_xref % - verify_xref -
+{ PDFfilelen
+ 1 1 Objects length 1 sub % stack: filesize 1 1 <number of objects - 1>
+ { % Check if the object is free (i.e. not used). The values in
+ % Generations is the generation number plus 1. If the value in
+ % Generations is zero then the object is free.
+ % Stack: <filesize> <obj num>
+ Generations 1 index get % Get the genration number
+ 0 ne { % Skip if object number is free
+ ObjectStream 1 index get % Check if object is in objectstream
+ 0 eq { % We only check objects not in an objectstream
+ { % Use stop context since we may get an error if object is invalid
+ dup Objects exch get % Get the object location
+ PDFoffset add dup 3 index ge % Compare object location to file size
+ { pop //true } % Rebuild if location not in file
+ { PDFfile exch setfileposition % Go to the object location
+ //true % Stack: <filesize> <obj num> <true>
+ PDFfile token pop % Read object number from file
+ 2 index eq { % Verify object number
+ PDFfile token pop % Read generation number from file
+ Generations 3 index % Get specified generaton number
+ get 1 sub % Gen numbs are stored with 1 added.
+ eq { % Verify generation number
+ PDFfile token pop
+ /obj eq { % Verify 'obj' text
+ pop //false % We have valid object, do not rebuild
+ } if
+ } if
+ } if
+ } ifelse
+ } .internalstopped
+ { //true } if % If we stop then we need to rebuild
+ % Stack: <filesize> <obj num> <need rebuild flag>
+ {
+ ( **** Warning: File has an invalid xref entry: )
+ pdfformatwarning
+ pdfstring cvs pdfformatwarning
+ (. Rebuilding xref table.\n) pdfformatwarning
+ search_objects
+ exit
+ } if % If the entry is invalid
+ } {
+ % The object is in an object stream. We currently do not rebuild
+ % objects in an object stream. So If we find one, then abort the
+ % verification of the xref table entries.
+ pop exit % Pop object number and then exit loop
+ } ifelse % If not in an object stream
+ } if % If object entry is not free
+ pop % Remove object number
+ } for
+ pop % Remove the size of the file
+} bind odef
+
+/pdfopencache { % - pdfopencache -
+ % Create and initialize some caches.
+ /PageCount pdfpagecount def
+ /PageNumbers PageCount 65534 .min dict def
+ /PageIndex PageCount 65534 .min array def
+} bind def
+
+/pdfopenfile { % <file> pdfopenfile <dict>
+ pdfdict readonly pop % can't do it any earlier than this
+ 32 dict begin
+ /LocalResources 0 dict def
+ /DefaultQstate //null def % establish binding
+ /Printed where { pop } {
+ % Guess whether the output device is a printer.
+ /Printed currentpagedevice /OutputFile known def
+ } ifelse
+ currentpagedevice /OutputFile known {
+ currentpagedevice /OutputFile get (%d) search {
+ pop pop pop
+ /NO_PDFMARK_OUTLINES true def
+ /NO_PDFMARK_DESTS true def
+ } {
+ pop
+ }ifelse
+ } if
+ /PSLevel1 where { pop } { /PSLevel1 //false def } ifelse
+ % NB: PDFfile is used outside of the PDF code to determine that a
+ % PDF job is being processed; to not change or hide this key.
+ cvlit /PDFfile exch def
+ /PDFsource PDFfile def
+ /Repaired //false def
+ /RepairedAnError //false def
+ /StreamRunAborted //false def
+ /NeedAppearances //false def
+ currentglobal //true .setglobal globaldict begin
+ /UndefProcList 0 dict def
+ end .setglobal
+ PDFfile dup 0 setfileposition
+ 0 () /SubFileDecode filter % to avoid file closure
+ pdfstring readstring pop
+ (%PDF-) search not {/pdfopen cvx /syntaxerror signalerror} if
+ length /PDFoffset exch def pop
+ % some badly formed PDF's (Visioneer) have something other than EOL
+ % after the version number. If we get an error, shorten the string
+ % and try again.
+ //false exch % error encountered
+ { { cvr } stopped
+ { exch pop //true exch 0 1 index length 1 sub dup 0 eq
+ { pop 0 exit } if % exit if string now empty
+ getinterval % trim character from right end and retry
+ }
+ { exch {
+ ( **** Warning: PDF version number not followed by EOL.\n)
+ pdfformatwarning
+ }
+ if exit
+ }
+ ifelse
+ } loop
+
+ /Classic-xref //true def
+ /PDFversion exch def
+ % Read the last cross-reference table.
+ count /pdfemptycount exch def
+ /Trailer << >> def % Initialize to an emptry dict.
+ {initPDFobjects findxref readxref}
+ PDFSTOPONERROR not {
+ .internalstopped {
+ recover_xref_data % Read failed. Attempt to recover xref data.
+ search_trailer % Search for the primary trailer
+ false % search_trailer sets up /Trailer, so don't run the code to do that...
+ } {
+ true
+ } ifelse
+ } {
+ exec true
+ } ifelse
+
+ {
+ /Trailer exch def % Save trailer dict after first xref table
+ % Read any previous cross-reference tables. When we are done,
+ % verify that the entries in the xref tables are valid if NoVerifyXref
+ % is not defined.
+ Trailer
+ { /Prev knownoget not { % If no previous xref table then ...
+ Classic-xref {
+ /NoVerifyXref where { pop } { verify_xref } ifelse
+ } if
+ exit
+ } if
+ { readxref }
+ PDFSTOPONERROR not {
+ .internalstopped {
+ recover_xref_data % Read failed. Attempt to recover xref data.
+ exit % Exit loop since recover gets all obj data.
+ } if % If readxref stopped
+ } {
+ exec
+ } ifelse
+ % The PDF spec. says that each trailer dict should contain the required
+ % entries. However we have seen a PDF file that only has a Prev entry in
+ % the initial trailer dict. Acrobat complains but it accepts these files.
+ % To work with these files, we are copying any entries which we find in
+ % a previous trailer dict which are not present in the initial dict.
+ dup {
+ Trailer 2 index known {
+ pop pop % discard if key already present
+ } {
+ Trailer 3 1 roll put % add key if not present
+ } ifelse
+ } forall
+ } loop % Loop to previous trailer
+ } if
+
+ /NumObjects Objects length def % To check that obj# < NumObjects
+
+ % Scan numbers in the range 2147483648..4294967295 in Encrypt dictionary
+ % as unsigned integers for compatibility with Acrobat Reader. Bug 689010.
+ << /PDFScanUnsigned //true >> setuserparams
+ { Trailer /Encrypt knownoget {
+ pop
+ pdf_process_Encrypt % signal error
+ } if
+ } stopped
+ << /PDFScanUnsigned //false >> setuserparams
+ { stop } if
+
+ % Check for recursion in the page tree. Bug 689954, MOAB-06-01-2007
+ verify_page_tree
+
+ currentdict end
+ } bind def
+
+%% Executing token on a file will close the file if we reach EOF while
+%% processing. When repairing broken files (or searching for startxref
+%% and the xref offset) we do *NOT* want this to happen, because that
+%% will close PDFfile and we don't have the filename to reopen it.
+/token_no_close { %% -file- token_no_close <any> true | false
+ dup type /filetype eq {
+ <<
+ /EODCount 2 index bytesavailable %% fix data length at underlying bytes
+ /EODString () %% make sure filter passes that many bytes, no EOD
+ /CloseSource false %% Be sure, tell the filter not to close the source file
+ >>
+ /SubFileDecode filter dup %% -filter- -filter-
+ token { %% -filter- <any> true | false
+ %% token returned a value
+ exch %% <any> filter
+ closefile %% <any>
+ true %% <any> true
+ }{
+ %% token didn't find a value
+ closefile %% -
+ false %% false
+ } ifelse
+ } {
+ token
+ } ifelse
+} bind def
+
+% Look for the last (startxref) from the current position
+% of the file. Return the position after (startxref) if found or -1 .
+/find-startxref { % <file> find_eof <file> <position>
+ -1
+ { 1 index dup 0 (startxref) /SubFileDecode filter flushfile
+ bytesavailable 9 lt { exit } if
+ pop dup fileposition
+ } loop
+} bind def
+
+% Search for the last 'startxfer' and read a following token, which
+% must be a number. Don't pay any attention to %%EOF because it's
+% often mangled.
+% There seems to be no limit on the amount of garbage that can be
+% appended to the PDF file. Current record (60K) belongs to
+% PDF-Out (v 2.0 - 35). We start the search from the last 1024
+% bytes and continue from the beginning of the file.
+/findxref { % - findxref <xrefpos>
+ PDFfile dup dup dup 0 setfileposition bytesavailable
+ dup /PDFfilelen exch def
+ % Find the last %%EOF string (within 1024 bytes)
+ 1024 sub PDFoffset .max
+ setfileposition find-startxref % file pos|-1 % search the last 1024 bytes
+ dup 0 le {
+ pop
+ dup PDFoffset setfileposition find-startxref % search from the beginnibg
+ dup 0 le {
+ ( **** Error: Cannot find a 'startxref' anywhere in the file.\n)
+ pdfformaterror
+ ( Output may be incorrect.\n) pdfformaterror
+ /findxref cvx /syntaxerror signalerror
+ } if
+ } if
+ 2 copy setfileposition
+ pop token_no_close not { //null } if
+ dup type /integertype ne {
+ ( **** Error: invalid token after startxref.\n) pdfformaterror
+ ( Output may be incorrect.\n) pdfformaterror
+ /findxref cvx /syntaxerror signalerror
+ } if
+} bind def
+
+/stderrfile (%stderr) (w) file def
+/stdoutfile (%stdout) (w) file def
+
+/stderrprint { % <string> stderrprint -
+ //stderrfile dup 3 -1 roll writestring flushfile
+} bind def
+
+/stdoutprint { % <string> stderrprint -
+ //stdoutfile dup 3 -1 roll writestring flushfile
+} bind def
+
+/pdfformaterror { % <string> pdfformaterror -
+ stdoutprint
+ /Repaired //true store
+ /RepairedAnError //true store
+} bind def
+
+/pdfformatwarning { % <string> pdfformaterror -
+ QUIET not {stdoutprint}{pop}ifelse
+ /Repaired //true store
+ PDFSTOPONWARNING {/warning cvx /undefined signalerror} if
+} bind def
+
+/knownoget_safe
+{ 2 copy knownoget { 3 1 roll pop pop //true } { pop pop //false } ifelse
+} odef
+
+/printProducer {
+ Trailer /Info { knownoget_safe } stopped { pop pop //false } if {
+ /Producer knownoget not { //null } if
+ } {
+ //null
+ } ifelse
+ dup //null eq {
+ pop
+ } {
+ ( **** The file was produced by: \n **** >>>> ) stderrprint
+ % Handle a Unicode Producer.
+ (\376\377) anchorsearch {
+ pop dup length 2 idiv string 0 1 2 index length 1 sub {
+ % Stack: origstr newstr i
+ 1 index exch 3 index 1 index 2 mul 1 add get put
+ } for exch pop
+ } if
+ stderrprint
+ ( <<<<\n) stderrprint
+ } ifelse
+} bind def
+% The UndefProcList collects noisy warnings.
+% This gets rid of many multiple warnings from pdf_font.ps
+/printCollectedWarnings {
+ UndefProcList length 0 gt {
+ (\n **** Embedded font uses undefined procedure\(s\): ) stderrprint
+ UndefProcList {
+ exch .namestring stderrprint ( ) stderrprint
+ =string cvs stderrprint ( times, ) stderrprint
+ } forall
+ (\n) stderrprint
+ } if
+} bind def
+
+/printrepaired {
+ QUIET not
+ {
+ printCollectedWarnings
+ (\n **** This file had errors that were repaired or ignored.\n)
+ stdoutprint
+ printProducer
+ ( **** Please notify the author of the software that produced this\n)
+ stdoutprint
+ ( **** file that it does not conform to Adobe's published PDF\n)
+ stdoutprint
+ ( **** specification.\n\n)
+ stdoutprint
+ } if
+} bind def
+
+/printrepairederror {
+ QUIET not
+ {
+ printrepaired
+ ( **** The rendered output from this file may be incorrect.\n)
+ stdoutprint
+ } if
+} bind def
+
+% Write the outline structure for a file. Uses linkdest (below).
+% omit links to pages that don't exist.
+/writeoutline % <outlinedict> writeoutline -
+ { mark
+ 0 2 index /First knownoget
+ { { exch 1 add exch /Next knownoget not { exit } if } loop }
+ if
+ % stack: dict mark count
+ dup 0 eq
+ { pop 1 index }
+ { 2 index /Count knownoget { 0 lt { neg } if } if
+ /Count exch 3 index
+ }
+ ifelse
+ {
+ dup /A knownoget {
+ dup /URI known {
+ /A mark 3 2 roll % <<>> /A [ <<action>>
+ { oforce } forall
+ .dicttomark
+ 3 2 roll
+ }
+ {
+ dup /S knownoget {
+ %% Because we process GoTo Destinations into absolute references in the PDF file
+ %% we need to resolve the /D or /Dest. However, we must *not* do this for
+ %% GoToR Destinations because (obviously) those are in a different file and
+ %% we cannot resolve them into absolute references. We don't need to anyway
+ %% because that file must already have a named destination.
+ dup /GoTo eq {
+ pop
+ dup /D knownoget {
+ exch pop exch dup length dict copy dup /Dest 4 -1 roll put
+ } if
+ }{
+ dup /GoToR eq {
+ pop /A mark % <<..action dict..>> /A [
+ 3 2 roll % /A [ <<..action dict..>>
+ { oforce } forall
+ .dicttomark
+ 3 2 roll
+ }{
+ dup /Launch eq {
+ pop /A mark % <<..action dict..>> /A [
+ 3 2 roll % /A [ <<..action dict..>>
+ { oforce } forall
+ .dicttomark
+ 3 2 roll
+ }{
+ /Named eq {
+ /N knownoget { % Assume /S /Named
+ namedactions exch .knownget { exec } if
+ } if
+ } if
+ } ifelse
+ } ifelse
+ } ifelse
+ } if
+ } ifelse
+ } if
+ linkdest
+ } stopped
+ {
+ cleartomark % ignore this link
+ ( **** Warning: Outline has invalid link that was discarded.\n)
+ pdfformatwarning
+ } {
+ /Title knownoget {
+ {/Title exch /OUT pdfmark} stopped {cleartomark} if
+ } {
+ cleartomark
+ ( **** Warning: Outline without /Title attribute was discarded.\n)
+ pdfformatwarning
+ } ifelse
+ }
+ ifelse
+ /First knownoget
+ { { dup writeoutline /Next knownoget not { exit } if } loop }
+ if
+ } bind def
+
+% Close a PDF file.
+/pdfclose % <dict> pdfclose -
+ { begin
+ PDFfile closefile
+ end
+ } bind def
+
+% ======================== Page accessing ======================== %
+
+% Get a (possibly inherited) attribute of a page.
+/pget % <pagedict> <key> pget <value> -true-
+ % <pagedict> <key> pget -false-
+ {
+ 2 copy knownoget
+ { exch pop exch pop //true }
+ { exch /Parent knownoget
+ { exch pget }
+ % finally see if the key is (misplaced) in the Root Catalog dict
+ { dup Trailer /Root oget exch knownoget dup {
+ 3 -1 roll ( **** Error: The /) pdfformaterror 50 string cvs pdfformaterror
+ ( key is missing from the Page tree.\n) pdfformaterror
+ ( Output may be incorrect.\n) pdfformaterror
+ }
+ { exch pop }
+ ifelse
+ }
+ ifelse
+ }
+ ifelse
+ } bind def
+
+% Get the value of a resource on a given page.
+/rget { % <resname> <pagedict> <restype> rget <value> -true-
+ % <resname> <pagedict> <restype> rget -false-
+ LocalResources 1 index knownoget {
+ 3 index knownoget
+ } {
+ //false
+ } ifelse {
+ exch pop exch pop exch pop //true
+ } {
+ 1 index /Resources pget {
+ 1 index knownoget { 3 index knownoget } { //false } ifelse
+ } {
+ //false
+ } ifelse {
+ 4 1 roll pop pop pop //true
+ } {
+ countdictstack array dictstack
+ //false 5 1 roll
+ dup length 1 sub -1 4 { % false /Name <<>> /Type [<<gstate>>] i
+ 1 index exch get % false /Name <<>> /Type [] <<gstate>>
+ /FormResDict .knownget { % false /Name <<>> /Type [] <<res>>
+ 2 index knownoget { % false /Name <<>> /Type [] <<type_dict>>
+ 4 index knownoget { % false /Name <<>> /type [] <<res_dict>>
+ ( **** Warning: resource was found only in an external (parent) context.\n) pdfformatwarning
+ //true 7 2 roll % <<res_dict>> true false /Name <<>> /Type []
+ pop exit
+ } if
+ } if
+ } if
+ } for
+ pop pop pop pop
+ } ifelse
+ } ifelse
+} bind def
+
+% Get the total number of pages in the document.
+/pdfpagecount % - pdfpagecount <int>
+ { Trailer /Root knownoget {
+ /Pages knownoget {
+ dup /Count knownoget {
+ dup type /integertype eq { dup 0 le } { //true } ifelse {
+ pop
+ dup /Kids knownoget {
+ pop
+ ( **** Warning: Invalid Page count.\n) pdfformatwarning
+ % find the last page and use that as the Count
+ 1 1 999999999 {
+ dup pdffindpage?
+ exch pop
+ //null eq { exit } { pop } ifelse
+ } for
+ 1 sub % decrement to last page that we were able to find
+ 2 copy /Count exch put
+ } {
+ 0 % return 0 and keep 0 page count.
+ ( **** Warning: PDF document has no pages.\n) pdfformatwarning
+ } ifelse
+ } if
+ exch pop
+ } {
+ dup /Type oget /Page eq {
+ << exch 1 array astore /Kids exch /Count 1 /Type /Pages >>
+ Trailer /Root oget /Pages 3 -1 roll put
+ 1
+ ( **** Warning: No /Pages node. The document /Root points directly to a page.\n)
+ pdfformatwarning
+ } {
+ ( **** Warning: Page count not found; assuming 1.\n)
+ pdfformatwarning
+ pop 1
+ } ifelse
+ } ifelse
+ } {
+ 0
+ }ifelse
+ }{
+ 0
+ } ifelse
+ } bind def
+
+% Check for loops in the 'page tree' but accept an acyclic graph.
+% - verify_page_tree -
+/verify_page_tree {
+ Trailer /Root knownoget {
+ /Pages knownoget {
+ 10 dict begin
+ /verify_page_tree_recursive {
+ dup 1 def
+ dup /Kids knownoget {
+ { oforce
+ dup //null ne {
+ currentdict 1 index known {
+ ( **** Error: there's a loop in the Pages tree. Giving up.\n) pdfformaterror
+ /verify_page_tree cvx /syntaxerror signalerror
+ } if
+ verify_page_tree_recursive
+ } {
+ pop
+ } ifelse
+ } forall
+ } if
+ currentdict exch undef
+ } def
+ verify_page_tree_recursive
+ end
+ } if
+ } if
+} bind def
+
+/pdffindpage? { % <int> pdffindpage? 1 null (page not found)
+ % <int> pdffindpage? 1 noderef (page found)
+ % <int> pdffindpage? 0 null (Error: page not found)
+ Trailer /Root oget /Pages get
+ { % We should be able to tell when we reach a leaf
+ % by finding a Type unequal to /Pages. Unfortunately,
+ % some files distributed by Adobe lack the Type key
+ % in some of the Pages nodes! Instead, we check for Kids.
+ dup oforce /Kids knownoget not { exit } if
+ exch pop //null
+ 0 1 3 index length 1 sub {
+ 2 index exch get
+ dup oforce dup /Kids known { /Count oget } { pop 1 } ifelse
+ % Stack: index kids null noderef count
+ dup 5 index ge { pop exch pop exit } if
+ 5 -1 roll exch sub 4 1 roll pop
+ } for exch pop
+ % Stack: index null|noderef
+ dup //null eq { pop pop 1 //null exit } if
+ } loop
+} bind def
+
+% Find the N'th page of the document by iterating through the Pages tree.
+% The first page is numbered 1.
+/pdffindpageref { % <int> pdffindpage <objref>
+ dup pdffindpage?
+ % Stack: index countleft noderef
+ 1 index 1 ne { pop pop /pdffindpage cvx /rangecheck signalerror } if
+ exch pop
+ PageIndex 2 index 1 sub 65533 .min 2 index oforce put
+ PageNumbers 1 index oforce 3 index dup 65534 le
+ { put }
+ { pop pop pop } % don't store more than 65534 pagenumbers
+ ifelse
+ exch pop
+} bind def
+/pdffindpage { % <int> pdffindpage <pagedict>
+ pdffindpageref oforce
+} bind def
+
+% Find the N'th page of the document.
+% The first page is numbered 1.
+/pdfgetpage % <int> pdfgetpage <pagedict>
+ { PageIndex 1 index 1 sub dup 65533 lt
+ { get }
+ { pop pop //null }
+ ifelse
+ dup //null ne
+ { exch pop oforce }
+ { pop pdffindpage }
+ ifelse
+ } bind def
+
+% Find the page number of a page object (inverse of pdfgetpage).
+/pdfpagenumber % <pagedict> pdfpagenumber <int>
+ { % We use the simplest and stupidest of all possible algorithms....
+ PageNumbers 1 index .knownget
+ { exch pop
+ }
+ { 1 1 PageCount 1 add % will give a rangecheck if not found
+ { dup pdfgetpage oforce 2 index eq { exit } if pop
+ }
+ for exch pop
+ }
+ ifelse
+ } bind def
+
+% Arrange the four elements that define a rectangle into a 'normal' order.
+/normrect_elems % <x1> <y1> <x2> <y2> normrect_elems <llx> <lly> <urx> <ury>
+{
+ 4 { % Bug 693919
+ dup type dup /integertype ne exch /realtype ne and {
+ ( **** Error: replacing malformed number ') pdfformaterror pdfstring cvs pdfformaterror
+ (' with 0.\n) pdfformaterror
+ ( Output may be incorrect.\n) pdfformaterror
+ 0
+ } if
+ 4 1 roll
+ } repeat
+ exch 4 1 roll % <x2> <x1> <y1> <y2>
+ 2 copy gt { exch } if % <x2> <x1> <lly> <ury>
+ 4 2 roll 2 copy lt { exch } if % <lly> <ury> <urx> <llx>
+ 4 1 roll exch % <llx> <lly> <urx> <ury>
+} bind def
+
+% Arrange a rectangle into a 'normal' order. I.e the lower left corner
+% followed by the upper right corner.
+/normrect % <rect> normrect <rect>
+{
+ aload pop normrect_elems 4 array astore
+} bind def
+
+/fix_empty_rect_elems % </Name> <x1> <y1> <x2> <y2> fix_empty_rect_elems <x1> <y1> <x2'> <y2'>
+{ dup 3 index eq { //true } { 1 index 4 index eq } ifelse {
+ pop pop pop pop
+ ( **** Warning: File has an empty ) pdfformaterror pdfstring cvs pdfformaterror
+ (. Using the current page size instead.\n) pdfformaterror
+ ( Output may be incorrect.\n) pdfformaterror
+ 0 0 currentpagedevice /PageSize get aload pop
+ } {
+ 5 -1 roll pop
+ } ifelse
+} bind def
+
+/boxrect % <llx> <lly> <urx> <ury> boxrect <x> <y> <w> <h>
+ { exch 3 index sub exch 2 index sub
+ } bind def
+/resolvedest { % <name|string|other> resolvedest <other|null>
+ dup type /nametype eq {
+ Trailer /Root oget /Dests knownoget {
+ exch knownoget not { //null } if
+ } {
+ pop //null
+ } ifelse
+ } {
+ dup type /stringtype eq {
+ Trailer /Root oget /Names knownoget {
+ /Dests knownoget {
+ exch nameoget
+ } {
+ pop //null
+ } ifelse
+ } {
+ pop //null
+ } ifelse
+ } if
+ } ifelse
+} bind def
+
+% Procedures to do the necessary transformations of view destinations
+% <PDF2PS_matrix> <rot> <view> -- <view'>
+/viewdestprocs 8 dict dup begin
+ /Fit { exch pop exch pop } bind def
+ /FitH {
+ aload length 2 lt {
+ 1 array astore
+ 3 1 roll pop pop
+ }{
+ 0 4 -1 roll 1 and 0 eq { exch } if
+ 4 -1 roll transform exch pop
+ 2 array astore
+ } ifelse
+ } bind def
+ /FitV {
+ aload length 2 lt {
+ 1 array astore
+ 3 1 roll pop pop
+ }{
+ 0 4 -1 roll 1 and 0 ne { exch } if
+ 4 -1 roll transform pop
+ 2 array astore
+ } ifelse
+ } bind def
+ /FitB /Fit load def
+ /FitBH /FitH load def
+ /FitBV /FitV load def
+ /XYZ {
+ dup length dup 4 gt {
+ pop /viewdestprocs cvx /rangecheck signalerror
+ }{
+ dup 4 eq {
+ pop aload pop
+ } {
+ dup 3 eq {
+ pop aload pop //null
+ } {
+ dup 2 eq {
+ pop aload pop //null //null
+ } {
+ dup 1 eq {
+ pop aload pop //null //null //null
+ } {
+ pop /viewdestprocs cvx /rangecheck signalerror
+ } ifelse
+ } ifelse
+ } ifelse
+ } ifelse
+ } ifelse
+ 3 1 roll
+ 2 copy 7 -1 roll 1 and 0 ne { exch } if 4 2 roll % odd rotation switches x<->y
+ 2 { dup //null eq { pop 0 } if exch } repeat % replace nulls with 0
+ 7 -1 roll transform % transform coordinates
+ 2 { 3 -1 roll //null eq { pop //null } if exch } repeat % put the nulls back
+ 3 -1 roll
+ 4 array astore
+ } bind def
+ /FitR {
+ exch pop
+ aload pop
+ 2 { 5 index transform 4 2 roll } repeat normrect_elems
+ 5 array astore
+ exch pop
+ } bind def
+end readonly def
+
+/linkdest { % <link|outline> linkdest
+ % ([/Page <n>] /View <view> | ) <link|outline>
+ dup /NewWindow knownoget {
+ /NewWindow exch 3 -1 roll
+ } if
+ dup /F knownoget {
+ /File exch 3 -1 roll
+ } if
+ dup /Dest knownoget
+ {
+ resolvedest
+ dup type /dicttype eq { /D knownoget not { //null } if } if
+ dup //null eq
+ { pop }
+ { dup 0 oget
+ //false % don't have a page# and transformation matrix (yet)
+ 1 index type /dicttype eq {
+ 1 index /Type knownoget {
+ /Page eq {
+ pop % the "false" flag
+ dup pdf_cached_PDF2PS_matrix exch
+ dup /Rotate pget not { 0 } if cvi 90 idiv exch
+ pdfpagenumber /CumulativePageCount where {pop CumulativePageCount}{0}ifelse add
+ //true % now we have a page# and a transformation matrix
+ } if
+ } if
+ } if
+ % stack: <link|outline> <dest> ( <PDF2PS_matrix> <rot> <page#> true | <page> false )
+ {
+ /Page exch 6 2 roll
+ % stack: [/Page <page#>] <link|outline> <dest> <PDF2PS_matrix> <rot>
+ 3 -1 roll dup length 1 sub 1 exch getinterval /View 4 1 roll
+ % stack: [/Page <page#>] <link|outline> /View <PDF2PS_matrix> <rot> <view>
+ //viewdestprocs 1 index 0 get get exec
+ 3 -1 roll
+ } {
+ dup type /integertype eq {
+ /CumulativePageCount where {pop CumulativePageCount}{0}ifelse add
+ /Page exch 1 add 4 2 roll
+ } {
+ pop
+ } ifelse
+ dup length 1 sub 1 exch getinterval /View exch 3 -1 roll
+ } ifelse
+ }
+ ifelse
+ }
+ if
+} bind def
+% <pagedict> mark ... -proc- <page#> <error>
+/namedactions 8 dict dup begin
+ /FirstPage { 1 /CumulativePageCount where {pop CumulativePageCount}{0}ifelse add //false } def
+ /LastPage { pdfpagecount /CumulativePageCount where {pop CumulativePageCount}{0}ifelse add //false } def
+ /NextPage { counttomark 2 add index pdfpagenumber 1 add dup pdfpagecount gt exch /CumulativePageCount where {pop CumulativePageCount}{0}ifelse add exch} bind def
+ /PrevPage { counttomark 2 add index pdfpagenumber 1 sub dup 1 lt exch /CumulativePageCount where {pop CumulativePageCount}{0}ifelse add exch} bind def
+end readonly def
+% <pagedict> <annotdict> -proc- -
+/annottypes 5 dict dup begin
+ /Text {
+ mark exch
+ { /Rect /Open /Contents /F}
+ { 2 copy knownoget { 3 -1 roll } { pop } ifelse }
+ forall pop {/ANN pdfmark} stopped {cleartomark} if
+ } bind def
+ /Link {
+ /NO_PDFMARK_DESTS where {pop NO_PDFMARK_DESTS not}{true}ifelse
+ {
+ mark exch
+ dup /BS knownoget { << exch { oforce } forall >> /BS exch 3 -1 roll } if
+ dup /F knownoget { /F exch 3 -1 roll } if
+ dup /C knownoget { /Color exch 3 -1 roll } if
+ dup /Rect knownoget { /Rect exch 3 -1 roll } if
+ dup /Border knownoget {
+ dup type /arraytype eq {
+ dup length 3 lt
+ } {
+ //true
+ } ifelse {
+ pop [ 0 0 0 ] % Following AR5 use invisible border.
+ } if
+ /Border exch 3 -1 roll
+ } if
+ dup /A knownoget {
+ dup /URI known {
+ /A mark 3 2 roll % <<>> /A [ <<action>>
+ { oforce } forall
+ .dicttomark
+ 3 2 roll
+ } {
+ dup /S knownoget {
+ %% Because we process GoTo Destinations into absolute references in the PDF file
+ %% we need to resolve the /D or /Dest. However, we must *not* do this for
+ %% GoToR Destinations because (obviously) those are in a different file and
+ %% we cannot resolve them into absolute references. We don't need to anyway
+ %% because that file must already have a named destination.
+ dup /GoTo eq {
+ pop
+ dup /D knownoget {
+ exch pop exch dup length dict copy dup /Dest 4 -1 roll put
+ } if
+ }{
+ dup /GoToR eq {
+ pop /A mark % <<..action dict..>> /A [
+ 3 2 roll % /A [ <<..action dict..>>
+ { oforce } forall
+ .dicttomark
+ 3 2 roll
+ }{
+ dup /Launch eq {
+ pop /A mark % <<..action dict..>> /A [
+ 3 2 roll % /A [ <<..action dict..>>
+ { oforce } forall
+ .dicttomark
+ 3 2 roll
+ }{
+ /Named eq {
+ /N knownoget {
+ namedactions exch .knownget {
+ exec {
+ pop
+ ( **** Warning: Ignoring a named action pointing out of the document page range.\n)
+ pdfformatwarning
+ } {
+ /Page exch 3 -1 roll
+ } ifelse
+ } if
+ } if
+ } if
+ }ifelse
+ } ifelse
+ } ifelse
+ } if
+ } ifelse
+ } if
+ { linkdest } stopped {
+ cleartomark
+ ( **** Warning: Link annotation points out of the document page range.\n)
+ pdfformatwarning
+ } {
+ pop {/LNK pdfmark} stopped {cleartomark} if
+ } ifelse
+ }{pop} ifelse
+ } bind def
+end readonly def
+
+% **** The following procedure should not be changed to allow clients
+% **** to directly interface with the constituent procedures. GSview
+% **** and some Artifex customers rely on the pdfshowpage_init,
+% **** pdfshowpage_setpage, pdfshowpage_finish so all logic should be
+% **** implemented in one of those three procedures.
+/pdfshowpage % <pagedict> pdfshowpage -
+ { dup /Page exch store
+ pdfshowpage_init % <pagedict>
+ pdfshowpage_setpage % <pagedict>
+ pdfshowpage_finish % -
+ } bind def
+
+/pdfpagecontents % <pagedict> pdfpagecontents <contents>
+ { } bind def
+
+/pdfshowpage_init % <pagedict> pdfshowpage_init <pagedict>
+ { /DSCPageCount DSCPageCount 1 add store
+ } bind def
+
+/get_media_box { % <pagedict> get_media_box <box> <bool>
+ /MediaBox pget {
+ oforce_array //true
+ } {
+ ( **** Error: Page has no /MediaBox attribute. Using the current page size.\n)
+ pdfformaterror
+ ( Output may be incorrect.\n) pdfformaterror
+ [ 0 0 currentpagedevice /PageSize get aload pop ] //false
+ } ifelse
+} bind def
+
+/get_any_box { % <pagedict> get_any_box <box name> <box>
+ //systemdict /UseBleedBox .knownget dup { and } if {
+ dup /BleedBox pget {
+ /BleedBox exch
+ } if
+ } if
+ //systemdict /UseTrimBox .knownget dup { and } if {
+ dup /TrimBox pget {
+ /TrimBox exch
+ } if
+ } if
+ dup type /arraytype ne {
+ //systemdict /UseArtBox .knownget dup { and } if {
+ dup /ArtBox pget {
+ /ArtBox exch
+ } if
+ } if
+ } if
+ dup type /arraytype ne {
+ //systemdict /UseCropBox .knownget dup { and } if {
+ dup /CropBox pget {
+ /CropBox exch
+ } if
+ } if
+ } if
+ dup type /arraytype ne {
+ /MediaBox exch get_media_box pop
+ } {
+ oforce_elems % <<pdict>> /SomeBox x0 y0 x1 y1
+ 6 -1 roll get_media_box { % /SomeBox x0 y0 x1 y1 [MediaBox]
+ aload pop % /SomeBox x0 y0 x1 y1 X0 Y0 X1 Y1
+ 5 -1 roll .min exch % /SomeBox x0 y0 x1 X0 Y0 mY1 X1
+ 5 -1 roll .min exch % /SomeBox x0 y0 X0 Y0 mX1 mY1
+ 4 2 roll % /SomeBox x0 y0 mX1 mY1 X0 Y0
+ 5 -1 roll .max exch % /SomeBox x0 mX1 mY1 mY0 X0
+ 5 -1 roll .max exch % /SomeBox mX1 mY1 mX0 mY0
+ 4 2 roll % /SomeBox mX0 mY0 mX1 mY1
+ } {
+ pop
+ } ifelse
+ 4 array astore % /SomeBox [mX0 mY0 mX1 mY1]
+ } ifelse
+} bind def
+
+% Compute the matrix that transforms the PDF->PS "default" user space
+/pdf_PDF2PS_matrix { % <pdfpagedict> -- matrix
+ matrix currentmatrix matrix setmatrix exch
+ % stack: savedCTM <pdfpagedict>
+ dup get_any_box
+ % stack: savedCTM <pdfpagedict> /Trim|Crop|Art|MediaBox <Trim|Crop|Art|Media Box>
+ oforce_elems normrect_elems fix_empty_rect_elems 4 array astore
+ //systemdict /PDFFitPage known {
+ PDFDEBUG { (Fiting PDF to imageable area of the page.) = flush } if
+ currentpagedevice /.HWMargins get aload pop
+ currentpagedevice /PageSize get aload pop
+ % Adjust PageSize and .HWMargins for the page portrait/landscape orientation
+ 2 copy gt % PageSize_is_landscape
+ 7 index aload pop 3 -1 roll sub 3 1 roll exch sub exch
+ 10 index /Rotate pget not { 0 } if cvi 90 idiv 1 and 0 ne { exch } if
+ gt % Box_is_landscape
+ xor % PageSize_is_landscape(or square) xor'ed with Box_is_lanscape suggests rotate
+ 2 index 2 index eq not and { % don't rotate if Page is square
+ 1 index 0 translate 90 rotate % add in a rotation
+ PDFDEBUG { ( Rotating the page for best fit) = flush } if
+ 2 copy ne {
+ % rotate the .HWMargins
+ 2 copy lt {
+ 6 2 roll 4 -1 roll 6 -2 roll
+ } {
+ 6 2 roll 4 1 roll 6 -2 roll
+ } ifelse
+ % rotate the page dimensions
+ exch
+ } if
+ } if
+ 3 -1 roll sub 3 1 roll exch sub exch
+ % stack: savedCTM <pdfpagedict> <Crop|Media Box> Xmin Ymin Xmax Ymax
+ PDFDEBUG { ( Translate up by [ ) print 3 index =print (, ) print 2 index =print ( ]) = flush } if
+ 3 index 3 index translate % move origin up to imageable area
+ 2 index sub exch 3 index sub exch 4 2 roll pop pop
+ % stack: savedCTM <pdfpagedict> [Box] XImageable YImageable
+ 2 index aload pop 2 index sub exch 3 index sub exch 4 2 roll pop pop
+ 5 index /Rotate pget not { 0 } if 90 cvi idiv 1 and 0 ne { exch } if
+ % stack: savedCTM <pdfpagedict> [Box] XImageable YImageable XBox YBox
+ 4 copy
+ 3 -1 roll exch div 3 1 roll div .min
+ % stack: savedCTM <pdfpagedict> [Box] XImageable YImageable XBox YBox scale
+ PDFDEBUG { ( Scale by ) print dup = flush } if
+ 5 -4 roll
+ % stack: savedCTM <pdfpagedict> [Box] scale XImageable YImageable XBox YBox
+ 3 index 2 index 6 index mul sub 2 div 3 index 2 index 7 index mul sub 2 div
+ PDFDEBUG { ( Centering translate by [ ) print 1 index =print (, ) print dup =print ( ]) = flush } if
+ translate pop pop pop pop
+ } {
+ //systemdict /NoUserUnit .knownget not { //false } if {
+ 1
+ } {
+ 1 index /UserUnit knownoget {
+ PDFDEBUG { (Scaling due to UserUnit by ) print dup = flush } if
+ } {
+ 1
+ } ifelse
+ } ifelse
+ } ifelse
+ % stack: savedCTM <pdfpagedict> [Box] scale
+ dup scale
+ % Rotate according to /Rotate
+ aload pop boxrect
+ {
+ { pop pop }
+ { -90 rotate pop neg 0 translate }
+ { 180 rotate neg exch neg exch translate }
+ { 90 rotate neg 0 exch translate pop }
+ }
+ 5 index /Rotate pget not { 0 } if cvi
+ PDFDEBUG { dup 0 ne { (Rotating by ) print dup =print ( degrees.) = flush } if } if
+ 90 idiv 3 and get exec
+ % Now translate to the origin given in the Crop|Media Box
+ exch neg exch neg translate
+ % stack: savedCTM <pdfpagedict>
+ pop
+ matrix currentmatrix exch setmatrix
+} bind def
+
+% Cache the matrix that transforms the PDF->PS "default" user space
+% into <pdfpagedict> under the key //PDF2PS_matrix_key, then return it
+/PDF2PS_matrix_key (PDF->PS matrix) cvn def
+/pdf_cached_PDF2PS_matrix { % <pdfpagedict> -- <PDF2PS_matrix>
+ dup //PDF2PS_matrix_key .knownget {
+ exch pop
+ } {
+ dup dup pdf_PDF2PS_matrix //PDF2PS_matrix_key exch put
+ //PDF2PS_matrix_key get
+ } ifelse
+} bind def
+currentdict /PDF2PS_matrix_key undef
+
+/.pdfshowpage_Install { % <pagedict> [<prevproc>] .pdfshowpage_Install -
+ 0 get exec
+ pdf_cached_PDF2PS_matrix concat
+} bind def
+
+/pdfshowpage_setpage { % <pagedict> pdfshowpage_setpage <pagedict>
+ 6 dict begin % for setpagedevice
+ % Stack: pdfpagedict
+ % This comment is no longer true, and is maintained here for history only:
+ %
+ % UseCIEColor is always true for PDF; see the comment in runpdf above
+ %
+ % We now test the page to see if it defines any Default* colour spaces and
+ % only set UseCIEColor if it does. This prevents a spurious warning from
+ % pdfwrite about not using UseCIEColor with pdfwrite.
+ %
+ pdfshowpage_detect_cspacesub {
+ /UseCIEColor //true def
+ } if
+
+ % Only lock in Orientation if we need to for pdfmarks
+ .writepdfmarks { /Orientation 0 def } if
+ currentpagedevice
+ % Stack: pdfpagedict currentpagedevicedict
+ 1 index get_any_box
+ % Stack: pdfpagedict currentpagedevicedict /BoxName [box]
+ oforce_elems normrect_elems fix_empty_rect_elems boxrect 4 2 roll pop pop
+ 3 index /Rotate pget not { 0 } if cvi 90 idiv 1 and 0 ne { exch } if
+ % stack: pdfpagedict currentpagedevicedict boxwidth boxheight
+ //systemdict /PDFFitPage known {
+ % Preserve page size,
+ % but choose portrait/landscape depending on box width:height ratio
+ % (if box width == height, select portrait orientation)
+ gt
+ 1 index /PageSize get aload pop
+ 2 copy gt
+ 4 -1 roll ne { exch } if
+ } {
+ % Set the page size.
+ //systemdict /NoUserUnit .knownget not { //false } if not {
+ 3 index /UserUnit knownoget {
+ dup 4 -1 roll mul 3 1 roll mul
+ } if
+ } if
+ } ifelse
+ 2 array astore /PageSize exch def
+ % Determine the number of spot colors used on the page. Note: This searches
+ % the pages resources. It may be high if a spot color is in a resource but
+ % is not actually used on the page.
+ currentpagedevice /PageSpotColors known { /PageSpotColors 2 index countspotcolors def } if
+
+ % Let the device know if we will be using PDF 1.4 transparency.
+ % The clist logic may need to adjust the size of bands.
+ 1 index pageusestransparency /PageUsesTransparency exch def
+ dup /Install .knownget {
+ % Don't let the Install procedure get more deeply
+ % nested after every page.
+ dup type dup /arraytype eq exch /packedarraytype eq or {
+ dup length 4 eq {
+ dup 2 get /.pdfshowpage_Install load eq {
+ 1 get 0 get % previous procedure
+ } if
+ } if
+ } if
+ } {
+ { }
+ } ifelse 1 array astore
+ 2 index exch /.pdfshowpage_Install load /exec load
+ 4 packedarray cvx
+ % Stack: pagedict currentpagedict installproc
+ /Install exch def
+ % Stack: pagedict currentpagedict
+ pop currentdict end setpagedevice
+} bind def
+
+/.free_page_resources { % - .free_page_resources -
+ Page /Resources pget {
+ /Shading knownoget {
+ { dup type /dicttype eq {
+ dup /.shading_dict known {
+ dup /.shading_dict undef
+ } if
+ } if
+ pop pop
+ } forall
+ } if
+ } if
+} bind def
+
+/pdfshowpage_finish { % <pagedict> pdfshowpage_finish -
+ save /PDFSave exch store
+ /PDFdictstackcount countdictstack store
+ /PDFexecstackcount count 2 sub store
+ (before exec) VMDEBUG
+
+ % set up color space substitution (this must be inside the page save)
+ pdfshowpage_setcspacesub
+
+ .writepdfmarks {
+
+ % Copy the boxes.
+ { /CropBox /BleedBox /TrimBox /ArtBox } {
+ 2 copy pget {
+ % .pdfshowpage_Install transforms the user space do same here with the boxes
+ oforce_elems
+ 2 { Page pdf_cached_PDF2PS_matrix transform 4 2 roll } repeat
+ normrect_elems 4 index 5 1 roll fix_empty_rect_elems 4 array astore
+ mark 3 1 roll {/PAGE pdfmark} stopped {cleartomark} if
+ } {
+ pop
+ } ifelse
+ } forall
+
+ % Copy annotations and links.
+ dup /Annots knownoget {
+ 0 1 2 index length 1 sub
+ { 1 index exch oget
+ dup type /dicttype eq {
+ dup /Subtype oget annottypes exch .knownget { exec } { pop } ifelse
+ } {
+ pop
+ } ifelse
+ }
+ for pop
+ } if
+
+ } if % end .writepdfmarks
+
+ % Display the actual page contents.
+ 9 dict begin
+ /BXlevel 0 def
+ /BMClevel 0 def
+ /OFFlevels 0 dict def
+ /BGDefault currentblackgeneration def
+ /UCRDefault currentundercolorremoval def
+ %****** DOESN'T HANDLE COLOR TRANSFER YET ******
+ /TRDefault currenttransfer def
+ matrix currentmatrix 2 dict
+ 2 index /CropBox pget {
+ oforce_elems normrect_elems boxrect
+ 4 array astore 1 index /ClipRect 3 -1 roll put
+ } if
+ dictbeginpage setmatrix
+ /DefaultQstate qstate store
+
+ count 1 sub /pdfemptycount exch store
+ % If the page uses any transparency features, show it within
+ % a transparency group. The scan was performed during pdfshowpage_setpage
+ % and the result was set in the pagedevice dictionary. Use it rather than
+ % scanning again IF it is present. If the pdfshowpage_setup was not called
+ % (eg GSView 5) then it will not be present, so we must rescan.
+ currentpagedevice /PageUsesTransparency .knownget not {dup pageusestransparency} if
+ dup /PDFusingtransparency exch def {
+ % If the current device isn't ProcessColorModel /DeviceCMYK, or if it is a
+ % HighLevelDevice (pdfwrite) we don't need the special handling of Overprint
+ % transparency, so disable the checking.
+ currentpagedevice dup /ProcessColorModel get /DeviceCMYK ne exch /HighLevelDevice known or {
+ /checkOPtrans { pop false } def % NB: original will be restored from PDFsave
+ } if
+ % Show the page within a PDF 1.4 device filter.
+ 0 .pushpdf14devicefilter {
+ /DefaultQstate qstate store % device has changed -- reset DefaultQstate
+ % If the page has a Group, enclose contents in transparency group.
+ % (Adobe Tech Note 5407, sec 9.2)
+ dup /Group knownoget {
+ 1 index /CropBox pget {
+ /CropBox exch
+ } {
+ 1 index get_media_box pop /MediaBox exch
+ } ifelse
+ oforce_elems normrect_elems fix_empty_rect_elems 4 array astore .beginformgroup
+ showpagecontents
+ .endtransparencygroup
+ } {
+ showpagecontents
+ } ifelse
+ } stopped {
+ % abort the transparency device
+ .abortpdf14devicefilter
+ /DefaultQstate qstate store % device has changed -- reset DefaultQstate
+ stop
+ } if
+ { } settransfer % identity transfer during popdevice (put_image)
+ .poppdf14devicefilter % NB: reset to DefaultQstate will also restore transfer function
+ /DefaultQstate qstate store % device has changed -- reset DefaultQstate
+ } {
+ /checkOPtrans { pop false } def % no-op the check if the page doesn't use transparency
+ % NB: original will be restored from PDFsave
+ showpagecontents
+ } ifelse
+ .free_page_resources
+ % todo: mixing drawing ops outside the device filter could cause
+ % problems, for example with the pnga device.
+ endpage
+ end % scratch dict
+ % Some PDF files don't have matching q/Q (gsave/grestore) so we need
+ % to clean up any left over dicts from the dictstack
+
+ PDFdictstackcount //false
+ { countdictstack 2 index le { exit } if
+ currentdict /n known not or
+ end
+ } loop {
+ StreamRunAborted not {
+ (\n **** Error: File has unbalanced q/Q operators \(too many q's\)\n Output may be incorrect.\n)
+
+ pdfdict /.Qqwarning_issued .knownget
+ {
+ {
+ pop
+ }
+ {
+ currentglobal pdfdict gcheck .setglobal
+ pdfdict /.Qqwarning_issued //true .forceput
+ .setglobal
+ pdfformaterror
+ } ifelse
+ }
+ {
+ currentglobal pdfdict gcheck .setglobal
+ pdfdict /.Qqwarning_issued //true .forceput
+ .setglobal
+ pdfformaterror
+ } ifelse
+ } if
+ } if
+ pop
+ count PDFexecstackcount sub { pop } repeat
+ (after exec) VMDEBUG
+ Repaired % pass Repaired state around the restore
+ RepairedAnError
+ PDFSave restore
+ currentglobal pdfdict gcheck .setglobal
+ pdfdict /.Qqwarning_issued //false .forceput
+ .setglobal
+ /RepairedAnError exch def
+ /Repaired exch def
+} bind def
+
+% Display the contents of a page (including annotations).
+/showpagecontents { % <pagedict> showpagecontents -
+ dup % Save the pagedict for the Annotations
+ count 1 sub /pdfemptycount exch store
+ gsave % preserve gstate for Annotations later
+ /Contents knownoget not { 0 array } if
+ dup type /arraytype ne { 1 array astore } if {
+ oforce dup type /dicttype eq {
+ //false resolvestream pdfopdict .pdfrun
+ } {
+ (**** Error: The Page /Contents array contains an element which is not a stream\n This page will not display correctly\n\n)
+ pdfformaterror
+ pop exit
+ }ifelse
+ } forall
+ % check for extra garbage on the ostack and clean it up
+ count pdfemptycount sub dup 0 ne {
+ ( **** Error: File did not complete the page properly and may be damaged.\n)
+ pdfformaterror
+ ( Output may be incorrect.\n) pdfformaterror
+ { pop } repeat
+ } {
+ pop
+ } ifelse
+ grestore
+ % Draw the annotations
+ //systemdict /ShowAnnots .knownget not { //true } if {
+ /Annots knownoget {
+ { oforce
+ dup //null ne {
+ .writepdfmarks
+ %%
+ %% We don't want to preserve annotations with ps2write, because we don't convert them
+ %% back into pdfmarks on output.
+ %%
+ /ForOPDFRead /GetDeviceParam .special_op {
+ exch pop
+ }{
+ //false
+ }ifelse
+ not
+ and
+ //systemdict /PreserveAnnots .knownget not {//true} if and {
+ mark exch {preserveannot} PDFSTOPONERROR {exec}{stopped {(Error: Ignoring invalid annotation, output may be incorrect.\n) pdfformaterror} if} ifelse cleartomark
+ }{
+ mark exch {drawannot} PDFSTOPONERROR {exec}{stopped {(Error: Ignoring invalid annotation, output may be incorrect.\n) pdfformaterror} if} ifelse cleartomark
+ } ifelse
+ } {
+ pop
+ } ifelse
+ } forall
+ } if
+ } if
+ //systemdict /ShowAcroForm .knownget { //true eq } { //false } ifelse {
+ Trailer /Root oget /AcroForm knownoget { draw_acro_form } if
+ } if
+} bind def
+
+/processcolorspace { % - processcolorspace <colorspace>
+ % The following is per the PLRM3.
+ currentdevice 1 dict dup /ProcessColorModel dup put .getdeviceparams
+ exch pop exch pop
+ dup type /nametype ne { cvn } if
+ dup { setcolorspace } .internalstopped { pop /DeviceRGB } if
+} bind def
+
+% ------ Transparency support ------ %
+
+% Determine whether a page might invoke any transparency features:
+% - Non-default BM, ca, CA, or SMask in an ExtGState
+% - Image XObject with SMask
+% Note: we deliberately don't check to see whether a Group is defined,
+% because Adobe Illustrator 10 (and possibly other applications) define
+% a page-level group whether transparency is actually used or not.
+% Ignoring the presence of Group is justified because, in the absence
+% of any other transparency features, they have no effect.
+%
+% Transparency is a 1.4 feature however we have seen files that claimed
+% to be PDF 1.1 with transparency features. Bugs 689288, 691273.
+/pageusestransparency { % <pagedict> pageusestransparency <bool>
+ NOTRANSPARENCY {
+ pop //false
+ } {
+ dup //false exch {
+ 4 dict 1 index resourceusestransparency { pop not exit } if
+ /Parent knownoget not { exit } if
+ } loop
+ % Also check for transparency in the annotation (if not in resources).
+ { pop //true } { annotsusetransparency } ifelse
+ } ifelse
+} bind def
+
+% Check if transparency is specified in an ExtGState dict
+/extgstateusestransparency { % <gstate dict> extgstateusestransparency <bool>
+ //false exch % Assume no transparency
+ dup //null eq {
+ pop % bug 692050
+ } {
+ { % establish loop context
+ dup /BM knownoget {
+ dup /Normal ne exch /Compatible ne and { pop not exit } if
+ } if
+ dup /ca knownoget { 1 ne { pop not exit } if } if
+ dup /CA knownoget { 1 ne { pop not exit } if } if
+ dup /SMask knownoget { /None ne { pop not exit } if } if
+ pop exit
+ } loop
+ } ifelse
+} bind def
+
+% Check if transparency is used in a Pattern
+/patternusestransparency { % <Pattern dict> patternusestransparency <bool>
+ dup //null eq NOTRANSPARENCY or
+ { pop //false }
+ { //false exch % Assume no transparency
+ {
+ 4 dict 1 index resourceusestransparency { pop not exit } if
+ dup /ExtGState knownoget { extgstateusestransparency { pop not exit } if } if
+ pop exit
+ } loop
+ }
+ ifelse
+} bind def
+
+% Check the Resources of a page or Form. Check for loops in the resource chain.
+/resourceusestransparency { % <dict> <dict> resourceusestransparency <bool>
+ { % Use loop to provide an exitable context.
+ /Resources knownoget not { 0 dict } if
+ 2 copy .knownget {
+ { % Some circular references may be missed because scanning stops
+ % when the 1st transparency is found.
+ ( **** Warning: Found circular references in resource dictionaries while checking for transparency.\n)
+ pdfformatwarning
+ } if
+ pop //false exit
+ } if
+ 2 copy //true put % In the current chain.
+ dup /ExtGState knownoget {
+ //false exch
+ { exch pop oforce extgstateusestransparency { pop //true exit } if
+ } forall
+ { pop //true exit } if
+ } if
+ dup /Pattern knownoget {
+ //false exch
+ { exch pop oforce patternusestransparency { pop //true exit } if
+ } forall
+ { pop //true exit } if
+ } if
+ dup /XObject knownoget {
+ dup type /dicttype eq {
+ //false exch
+ {
+ exch pop oforce
+ dup //null ne {
+ dup type /dicttype eq {
+ dup /Subtype get
+ dup /Image eq {
+ 1 index /SMask oknown { pop pop not exit } if
+ 1 index /SMaskInData knownoget {
+ 0 ne { pop pop not exit } if
+ } if
+ } if
+ /Form eq {
+ dup /Group known {pop pop true exit}{
+ 3 index exch resourceusestransparency { not exit } if
+ } ifelse
+ } {
+ pop
+ } ifelse
+ } {
+ pop
+ ( **** Warning: Ignoring non-dictionary /XObject attribute while checking for transparency.\n)
+ pdfformatwarning
+ } ifelse
+ } {
+ pop
+ } ifelse
+ } forall
+ { pop //true exit } if
+ } {
+ ( **** Warning: Ignoring non-dictionary /XObject while checking for transparency.\n)
+ pdfformatwarning
+ pop
+ } ifelse
+ } if
+ 2 copy //false put % Visited but not in the current chain.
+ pop //false exit
+ } loop
+ exch pop
+} bind def
+
+% Check if the annotations on a page use transparency
+/annotsusetransparency { % <page dict> annotsusetransparency <bool>
+ //false exch % Assume no transparency
+ /Annots knownoget { % Get Annots array
+ {
+ oforce
+ dup //null ne {
+ dup /Subtype knownoget {
+ /Highlight eq { % Highlight annotation is always implemented
+ pop pop //true exit % as transparency.
+ } if
+ } if
+ dup /AP knownoget { % Get appearance dict for the annoation
+ /N knownogetdict { % Get the /N (i.e. normal) appearance stream
+ 4 dict exch resourceusestransparency { pop pop //true exit } if
+ } if
+ } if % If AP dict known
+ dup /CA knownoget {
+ 1 le {
+ pop pop //true exit
+ } if
+ } if
+ /ca knownoget {
+ 1 le {
+ pop //true exit
+ } if
+ } if
+ } {
+ pop
+ } ifelse
+ } forall % For all annots on the page
+ } if
+} bind def
+
+% Add a color name to our spot color list. Ignore /All and /None
+/putspotcolor { % <name> <spotcolordict> putspotcolor -
+ % The 'name' could be a string. If so then convert to a name.
+ exch dup type /stringtype eq { cvn } if
+ dup dup /None eq exch /All eq or { pop pop } { 0 put } ifelse
+} bind def
+
+% Determine which spot colors are used within a color space Note: This
+% dict will include all colors used in Separation or DeviceN color spaces.
+% Thus it may include Cyan, Magenta, Yellow, and Black.
+% <colorspace> <spotcolordict> colorspacespotcolors -
+/colorspacespotcolors {
+ exch dup type /arraytype eq {
+ % If we have an Indexed color space then get the base space.
+ dup 0 oget % <<>> [csp] /Type
+ dup /Indexed eq {
+ pop 1 oget % <<>> [base]
+ 2 copy exch colorspacespotcolors
+ } {
+ % Stack: <spotcolordict> <colorspace> <colorspacetype>
+ dup /Separation eq exch /DeviceN eq or {
+ dup 1 oget dup type /arraytype eq {
+ { oforce 2 index putspotcolor } forall
+ } {
+ 2 index putspotcolor
+ } ifelse
+ } if
+ } ifelse
+ } if
+ pop pop
+} bind def
+
+% Check the Resources of a page, form, or annotation. Determine which spot
+% colors are used within the resource Note: The spot color dict will include
+% all colors used in Separation or DeviceN color spaces. Thus it may include
+% Cyan, Magenta, Yellow, and Black. We also pass a dict that is used to check
+% for loops in the resource list.
+% <spotcolordict> <loopdict> <page/form/annot dict>
+% resourcespotcolors <spotcolordict> <loopdict>
+/resourcespotcolors {
+ { % Use loop to provide an exitable context.
+ % Exit if no Resources entry
+ /Resources knownoget not { exit } if
+ % Exit if we have already seen this dict
+ 2 copy known { pop exit } if
+
+ % Save the Resources dict into our loop checking dict.
+ 2 copy 0 put
+
+ % Scan resources that might contain a color space.
+ dup /ColorSpace knownoget {
+ { exch pop oforce 3 index colorspacespotcolors } forall
+ } if
+ dup /Pattern knownoget {
+ { exch pop oforce
+ dup /Shading knownoget {
+ exch pop
+ /ColorSpace oget 3 index colorspacespotcolors
+ } {
+ 4 copy exch pop resourcespotcolors pop pop pop
+ } ifelse
+ } forall
+ } if
+ dup /Shading knownoget {
+ { exch pop
+ oforce /ColorSpace
+ { oget } stopped
+ {
+ pop pop
+ ( **** Error: invalid color space in shading, output may be incorrect.\n) pdfformaterror
+ }
+ { 3 index colorspacespotcolors}
+ ifelse
+ } forall
+ } if
+ /XObject knownoget {
+ dup type /dicttype eq {
+ { exch pop oforce
+ dup type /dicttype eq {
+ dup //null ne {
+ dup /Subtype oget
+ dup /Form eq {
+ pop resourcespotcolors
+ } {
+ /Image eq {
+ /ColorSpace knownoget {
+ 2 index colorspacespotcolors
+ } if
+ } {
+ pop
+ } ifelse
+ } ifelse
+ } {
+ pop
+ } ifelse
+ } {
+ pop
+ } ifelse
+ } forall
+ } {
+ pop % Just ignore here, already reported by resourceusestransparency.
+ } ifelse
+ } if
+ exit
+ } loop
+} bind def
+
+% Determine which spot colors are used within the annotations. Note: This
+% dict will include all colors used in Separation or DeviceN color spaces.
+% Thus it may include Cyan, Magenta, Yellow, and Black.
+% <spotcolordict> <loopdict> <annotsarray>
+% annotsspotcolors <spotcolordict> <loopdict>
+/annotsspotcolors {
+ { oforce
+ dup //null ne {
+ /AP knownoget { % Get appearance dict for the annoation
+ /N knownogetdict { % Get the /N (i.e. normal) appearance stream
+ resourcespotcolors
+ } if % If normal appearance streamknown
+ } if % If AP dict known
+ } {
+ pop
+ } ifelse
+ } forall
+} bind def
+
+% Determine spot colors are used within a page. We are creating a dict to
+% hold the spot color names as keys. Using a dict avoids having to worry
+% about duplicate entries. The keys in the dict contain the spot color
+% names. However the values have no meaning. Note: This dict will include
+% all colors used in Separation or DeviceN color spaces specified in the
+% page's resources. Thus it may include Cyan, Magenta, Yellow, and Black.
+% There is no attempt to verify that these color spaces are actually used
+% within the object streams for the page.
+/pagespotcolors { % <pagedict> pagespotcolors <spotcolordict>
+ dup
+ % Create a dict to hold spot color names.
+ 0 dict exch
+ % Create a dict to be used to check for reference loops.
+ 4 dict exch
+ % Check for color spaces in the Resources
+ resourcespotcolors
+ % now check upwards in the object hierarchy in case of inherited resources
+ 2 index
+ {
+ /Parent knownoget
+ {
+ dup 4 1 roll
+ resourcespotcolors
+ 3 -1 roll
+ }
+ {
+ exit
+ } ifelse
+ } loop
+ % Also check for color spaces in the annotations.
+ 3 -1 roll
+ /Annots knownoget { annotsspotcolors } if
+ pop % Discard reference loop dict
+} bind def
+
+% Determine how many (if any) spot colors are used by a page.
+% Note: This count does not include Cyan, Magenta, Yellow, or Black
+/countspotcolors { % <pagedict> countspotcolors <count>
+ pagespotcolors % Get dict with all spot colors
+ dup length % spot color dict length
+ % Remove CMYK from the spot color count.
+ [ /Cyan /Magenta /Yellow /Black ]
+ { 2 index exch known { 1 sub } if } forall
+ exch pop % Remove spot color dict
+} bind def
+
+% ------ ColorSpace substitution support ------ %
+
+%%
+%% <pagedict> pdf_colorspace_detect_cspacesub <boolean>
+%%
+/pdf_colorspace_detect_cspacesub {
+ //false exch
+ /Resources knownoget {
+ /ColorSpace knownoget {
+ dup /DefaultGray knownoget {
+ resolvecolorspace csncomp 1 eq {
+ pop pop //true
+ } if
+ } {
+ dup /DefaultRGB knownoget {
+ resolvecolorspace csncomp 3 eq {
+ pop pop //true
+ } if
+ } {
+ /DefaultCMYK knownoget {
+ resolvecolorspace csncomp 4 eq {
+ pop //true
+ } if
+ } if
+ } ifelse
+ } ifelse
+ } if
+ } if
+} bind def
+
+%%<Objectdict> <calling obj_num> pdfform_detect_cspacesub <boolean>
+%%
+/pdf_object_detect_cspacesub {
+ exch %% <calling obj_num> <Objectdict>
+ dup pdf_colorspace_detect_cspacesub {
+ pop //true
+ }{ %% <calling obj_num> <Objectdict>
+ /Resources knownoget { %% <calling obj_num> <Resourcesdict>
+ /XObject knownoget { %% <calling obj_num> <XObjectdict>
+ //false exch %% <calling obj_num> <XObjectdict> false
+ %% We have files where the XObject Resource is not a dictionary
+ dup type /dicttype eq { %% <calling obj_num> <XObjectdict> false
+
+ %% check each Xobject entry in the dictionary,
+ %% forall purs a key/value pair on the stack for us.
+ %%
+ { %% <calling obj_num> <XObjectdict> false key value
+ exch pop %% <calling obj_num> <XObjectdict> false value
+
+ %% If this is an indirect reference, check if its the smae object
+ %% as the current one. If its not indirect, make the object number 0
+ %% for comparison purposes.
+ dup type /packedarraytype eq {
+ dup 0 get dup 4 index
+ eq
+ } {
+ 0 false
+ }ifelse
+
+ %% <calling obj_num> <XObjectdict> false value <form object or 0 if not indirect> <boolean>
+ not {
+ %% swap object number and value, and dereference value
+ exch oforce
+ %% Apparently we have files where the content of the XObject Resource dictionary is null
+ dup //null ne {
+ %% and files where the indivudal XObjects are not dictionaries
+ dup type /dicttype eq {
+ dup /Subtype get /Form eq {
+ exch
+ pdf_object_detect_cspacesub {
+ pop //true exit
+ } if
+ } {
+ pop pop
+ }ifelse
+ }{
+ pop pop
+ } ifelse
+ }{
+ pop pop
+ }
+ ifelse
+ }{
+ pop pop
+ } ifelse
+ } forall
+ }{
+ pop
+ }ifelse
+ } {
+ %% No forms, so can't be any Default* spaces
+ //false
+ }ifelse
+ } {
+ //false
+ } ifelse
+ } ifelse
+ %% Remove the calling object ID, return our boolean
+ exch pop
+} bind def
+
+%
+% <pagedict> pdfshowpage_detect_cspacesub <pagedict> <boolean>
+%
+% this is used simply to detect whether the current page has any
+% Default* color spaces defined. If it does then we want pdfshowpage_setpage
+% to set UseCIEColor to true so that the Default* space is used. If the
+% page doesn't use any Default* spaces, then we *don't* want to set
+% UseCIEColor as that will confuse a warning in pdfwrite about
+% not using UseCIEColor with pdfwrite.
+%
+/pdfshowpage_detect_cspacesub {
+ dup 0 pdf_object_detect_cspacesub
+
+ /HighLevelDevice /GetDeviceParam .special_op {
+ exch pop not exch pop
+ }if
+
+} bind def
+
+%
+% <pagedict> pdfshowpage_setcspacesub <pagedict>
+%
+% Set up color space substitution for a page. Invocations of this procedure
+% must be bracketed by the save/restore operation for the page, to avoid
+% unintended effects on other pages.
+%
+% If any color space substitution is used, and the current color space is a
+% device dependent color space, make sure the current color space is updated.
+% There is an optimization in the setcolorspace operator that does
+% nothing if both the current and operand color spaces are the same. For
+% PostScript this optimization is disabled if the UseCIEColor page device
+% parameter is true. This is not the case for PDF, as performance suffers
+% significantly on some PDF files if color spaces are set repeatedly. Hence,
+% if color space substitution is to be used, and the current color space
+% is a device dependent color space, we must make sure to "transition" the
+% current color space.
+%
+/pdfshowpage_setcspacesub {
+ //false
+ /DefaultGray 2 index /ColorSpace //rget exec {
+ resolvecolorspace dup csncomp 1 eq {
+ dup type /nametype eq { 1 array astore } if
+ /DefaultGray exch /ColorSpace defineresource pop
+ pop //true
+ } {
+ pop
+ ( **** Error: ignoring invalid /DefaultGray color space.\n)
+ pdfformaterror
+ ( Output may be incorrect.\n) pdfformaterror
+ } ifelse
+ } if
+
+ /DefaultRGB 2 index /ColorSpace //rget exec {
+ resolvecolorspace dup csncomp 3 eq {
+ dup type /nametype eq { 1 array astore } if
+ /DefaultRGB exch /ColorSpace defineresource pop
+ pop //true
+ } {
+ pop
+ ( **** Error: ignoring invalid /DefaultRGB color space.\n)
+ pdfformaterror
+ ( Output may be incorrect.\n) pdfformaterror
+ } ifelse
+ } if
+
+ /DefaultCMYK 2 index /ColorSpace //rget exec {
+ resolvecolorspace dup csncomp 4 eq {
+ dup type /nametype eq { 1 array astore } if
+ /DefaultCMYK exch /ColorSpace defineresource pop
+ pop //true
+ } {
+ pop
+ ( **** Error: ignoring invalid /DefaultCMYK color space.\n)
+ pdfformaterror
+ ( Output may be incorrect.\n) pdfformaterror
+ } ifelse
+ } if
+
+ { % if using color space substitution, "transition" the current color space
+ currentcolorspace dup length 1 eq { % always an array
+ 0 get
+ dup /DeviceGray eq 1 index /DeviceRGB eq or 1 index /DeviceCMYK eq or {
+ /Pattern setcolorspace setcolorspace
+ } {
+ pop
+ } ifelse
+ } {
+ pop
+ } ifelse
+ } if
+} bind def
+
+% Write OutputIntents to device if the device handles it
+/writeoutputintents {
+ currentdevice 1 dict dup /OutputIntent //null put readonly
+ .getdeviceparams
+ mark ne { pop pop
+ % device supports OutputIntent parameter
+ % Make sure we don't have a badly broken PDF file!
+ Trailer /Root knownoget {
+ /OutputIntents knownoget {
+ dup type /arraytype eq {
+ { % process all output profiles present
+ oforce
+ dup length dict .copydict
+ dup /DestOutputProfile knownoget {
+ PDFfile fileposition exch
+ mark exch { oforce } forall .dicttomark
+ //true resolvestream
+ [ { counttomark 1 add index
+ 64000 string readstring
+ not { exit } if
+ } loop
+ ] exch closefile
+ 0 1 index { length add } forall .bytestring
+ 0 3 2 roll {
+ 3 copy putinterval
+ length add
+ } forall pop
+ exch PDFfile exch setfileposition
+ 1 index /DestOutputProfile 3 2 roll put
+ } if
+ % Convert to string array because it's easier for the device
+ [ 1 index /OutputCondition knownoget not { () } if
+ 2 index /OutputConditionIdentifier knownoget not { () } if
+ 3 index /RegistryName knownoget not { () } if
+ 4 index /Info knownoget not { () } if
+ 5 index /DestOutputProfile knownoget not { () } if
+ ]
+ [ /OutputIntent 3 2 roll /.pdfputparams where
+ { pop .pdfputparams }
+ { currentdevice //null //false counttomark 1 add 3 roll .putdeviceparamsonly }
+ ifelse
+ pop pop
+ pop % done with this OutputIntent dictionary
+ } forall
+ } {
+ pop
+ ( **** Error: /OutputIntent is of an incorrect type, ignoring OutputIntent.\n)
+ pdfformaterror
+ ( Output may be incorrect.\n) pdfformaterror
+ } ifelse
+ } if % OutputIntents known
+ % tell device there are no more OutputIntents
+ [ /OutputIntent [ ] /.pdfputparams where
+ { pop .pdfputparams }
+ { currentdevice //null //false counttomark 1 add 3 roll .putdeviceparamsonly }
+ ifelse
+ pop pop
+ } if
+ } if
+} bind def
+
+end % pdfdict
+.setglobal