summaryrefslogtreecommitdiff
path: root/sys/lib/ghostscript/pdf_main.ps
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 16:53:33 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 16:53:33 +0300
commite463eb40363ff4c68b1d903f4e0cdd0ac1c5977f (patch)
treed5e9f57c28f026cb21de3bd77cc10cd7f64aaa85 /sys/lib/ghostscript/pdf_main.ps
parentb41b9034225ab3e49980d9de55c141011b6383b0 (diff)
Import sources from 2011-03-30 iso image - sys/lib
Diffstat (limited to 'sys/lib/ghostscript/pdf_main.ps')
-rwxr-xr-xsys/lib/ghostscript/pdf_main.ps1337
1 files changed, 1337 insertions, 0 deletions
diff --git a/sys/lib/ghostscript/pdf_main.ps b/sys/lib/ghostscript/pdf_main.ps
new file mode 100755
index 000000000..c4c352085
--- /dev/null
+++ b/sys/lib/ghostscript/pdf_main.ps
@@ -0,0 +1,1337 @@
+% Copyright (C) 1994, 2000 Aladdin Enterprises. 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.
+%
+% For more information about licensing, please refer to
+% http://www.ghostscript.com/licensing/. For information on
+% commercial licensing, go to http://www.artifex.com/licensing/ or
+% contact Artifex Software, Inc., 101 Lucas Valley Road #110,
+% San Rafael, CA 94903, U.S.A., +1(415)492-9861.
+
+% $Id: pdf_main.ps,v 1.100 2005/09/23 18:21:23 ray Exp $
+% 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
+ % 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 { pop } bind
+ /BDC { pop pop } bind
+ /EMC { }
+ /MP { pop } bind
+ /DP { pop pop } 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
+ {
+ (%) eq {
+ dup ( ) .peekstring {
+ (%PDF-) eq {
+ dup (%stdin) (r) file eq {
+ % Copy PDF from stdin to temporary file then run it.
+ null (w+) //systemdict /.tempfile get 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
+ } {
+ cvx .runps % doesn't start with %PDF-
+ } ifelse
+ } {
+ pop cvx .runps % didn't read 5 characters
+ } ifelse
+ } {
+ cvx .runps % didn't start with %
+ } ifelse
+ } {
+ pop closefile % file was empty
+ } ifelse
+} bind odef
+currentdict /runpdfstring .undef
+
+
+/runpdfbegin { % <file> runpdf -
+ 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
+ 0 setobjectformat
+ /Page# null def
+ /Page null def
+ /DSCPageCount 0 def
+ /PDFSave null def
+ GS_PDF_ProcSet begin
+ pdfdict begin
+ pdfopen begin
+ Trailer /Root oget /Pages oget /CropBox knownoget
+ { oforce_array normrect mark /CropBox 3 -1 roll /PAGES pdfmark
+ }
+ if
+ /FirstPage where
+ { 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 { 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
+} bind def
+
+/dopdfpages { % firstpage# lastpage# dopdfpages -
+ << /PDFScanRules true >> setuserparams % set scanning rules for PDF vs. PS
+ 1 exch
+ { dup /Page# exch store
+ QUIET not { (Page ) print dup == flush } if
+ pdfgetpage pdfshowpage
+ } for
+ << /PDFScanRules null >> setuserparams % restore scanning rules for PS
+} bind def
+
+/runpdfend {
+ Repaired { printrepaired } if
+ currentdict pdfclose
+ end % temporary dict
+ end % pdfdict
+ end % GS_PDF_ProcSet
+ PDFTopSave restore
+ end % userdict
+} bind def
+
+/runpdf { % <file> runpdf -
+ runpdfbegin
+ dopdfpages
+ runpdfend
+} bind def
+
+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.
+
+/traileropdict mark
+ (<<) cvn { mark } bind
+ (>>) cvn { { .dicttomark } stopped {
+ ( **** File has unbalanced >> in trailer.\n) pdfformaterror
+ } 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
+ /startxref /exit load
+.dicttomark readonly def
+
+% Because of EOL conversion, lines with fixed contents might be followed
+% by one or more blanks.
+/lineeq % <filestr> <conststr> lineeq <bool>
+ { anchorsearch
+ { pop { ( ) anchorsearch not { () eq exit } if pop } loop }
+ { pop false }
+ ifelse
+ } bind def
+/linene { lineeq not } bind 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.
+ 0 % Initialize xref table error counter
+ { PDFfile token pop % first object # or trailer
+ dup /trailer eq { pop exit } if
+ PDFfile pdfstring readline pop
+ token pop % entry count
+ % remaining must be whitespace only (otherwise this xref Size was invalid.
+ exch dup length 0 ne {
+ false 1 index { 32 gt { pop true exit } if } forall {
+ ( **** Warning: xref subsection header has extra characters.\n)
+ pdfformaterror
+ /setxrefentry cvx /syntaxerror signalerror
+ } if
+ } if
+ pop % remove last
+ % 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 growPDFobjects
+ { % 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>
+ dup length 0 ne {
+ % check to make sure trailing garbage is just white space
+ dup { 32 gt { 5 -1 roll 1 add 5 1 roll } if } forall % bump error count on garbage
+ } if
+ pop % Stack: <err count> <obj#> <loc> <gen#> <tag>
+ dup /n eq { % xref line tag is /n
+ pop % pop dup of line tag
+ Objects 3 index lget null eq { % later update might have set it
+ 0 3 1 roll % Set ObjectStream object number = 0
+ setxrefentry % Save xref entry
+ 3 -1 roll pop % Remove ObjectStream object onumber
+ } if
+ }
+ { % 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 #>
+ } loop
+ 0 ne {
+ ( **** Warning: length of some xref entries is not equal to 20 bytes.\n)
+ pdfformaterror
+ } if
+ PDFfile traileropdict .pdfrun
+ } bind def
+
+ % 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
+ 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 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>
+ {
+ PDFfile exch setfileposition % move to start of object
+ % Get object number, revision, and 'obj' and discard
+ PDFfile token pop pop
+ PDFfile token pop pop
+ PDFfile token pop pop
+ % 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 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 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
+ { 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
+ .writepdfmarks {
+ % Copy bookmarks (outline) to the output.
+ Trailer /Root oget /Outlines knownoget {
+ /First knownoget {
+ { dup writeoutline /Next knownoget not { exit } if } loop
+ } if
+ } if
+ } if % end .writepdfmarks
+ currentdict end
+} 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 -
+{ 1 1 Objects llength 1 sub % stack: 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.
+ Generations 1 index lget % Get the genration number
+ 0 ne { % Skip if object number is free
+ ObjectStream 1 index lget % 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 lget % Get the object location
+ PDFoffset add PDFfile exch setfileposition
+ true % Stack: <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
+ lget 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
+ } .internalstopped
+ { true } if % If we stop then we need to rebuild
+ {
+ ( **** Warning: File has an invalid xref entry: )
+ pdfformaterror
+ pdfstring cvs pdfformaterror
+ (. Rebuilding xref table.\n) pdfformaterror
+ search_objects
+ exit
+ } if % If the entry is invalid
+ } if % If not in an object stream
+ } if % If object entry is not free
+ pop % Remove object number
+ } for
+} 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
+ 15 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
+ /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
+ currentglobal true .setglobal globaldict begin
+ /TTFWarnList 0 dict def /UndefProcList 0 dict def
+ end .setglobal
+ PDFfile dup 0 setfileposition pdfstring readstring
+ not {/pdfopen cvx /syntaxerror signalerror} if
+ (%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)
+ pdfformaterror
+ }
+ if exit
+ }
+ ifelse
+ } loop
+
+ /PDFversion exch def
+ % Read the last cross-reference table.
+ count /pdfemptycount exch def
+ /Trailer << >> def % Initialize to an emptry dict.
+ { initPDFobjects findxref readxref } .internalstopped {
+ recover_xref_data % Read failed. Attempt to recover xref data.
+ search_trailer % Search for the primary trailer
+ } {
+ /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 ...
+ /NoVerifyXref where { pop } { verify_xref } ifelse exit
+ } if
+ { readxref } .internalstopped {
+ recover_xref_data % Read failed. Attempt to recover xref data.
+ exit % Exit loop since recover gets all obj data.
+ } if % If readxref stopped
+ % 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
+ } ifelse % Ifelse readxref stopped
+ Trailer /Encrypt knownoget {
+ pop
+ pdf_process_Encrypt % signal error
+ } if
+ currentdict end
+ } bind def
+
+% Look for [\r\n]%%EO from the current position of the file.
+% Return the position of %%EO if found or -1 .
+/findeof { % <file> find_eof <file> <position>
+ -1 exch
+ {
+ dup bytesavailable 4 lt { exit } if
+ dup 0 (%%EO) /SubFileDecode filter flushfile
+ dup dup fileposition 5 sub setfileposition
+ dup 5 string readstring not { pop exit } if
+ dup (\r%%EO) eq exch (\n%%EO) eq or {
+ dup fileposition 4 sub
+ 3 1 roll exch pop
+ } if
+ } loop
+ exch
+} bind def
+
+% Skip backward over the %%EOF at the end of the PDF file, and read
+% the preceding startxref line. The PDF specification unambiguously
+% requires that the %%EOF appear on a line by itself, and that the
+% startxref and the following position value appear on separate lines;
+% however, some applications truncate the %%EOF to %%EO, and/or put the
+% startxref and the following value on the same line.
+% 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 for %%EO 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 findeof % search the last 1024 bytes
+ dup 0 le {
+ pop
+ dup PDFoffset setfileposition findeof % search from the beginnibg
+ dup 0 le {
+ ( **** Error: Cannot find a %%EOF marker anywhere in the file.\n)
+ pdfformaterror
+ /findxref cvx /syntaxerror signalerror
+ } if
+ } if
+ dup 3 1 roll setfileposition
+ % Stack: eofpos
+ % Check for whether this is, in fact, a valid PDF file.
+ dup PDFfilelen exch sub dup dup 7 gt exch 5 lt or {
+ pop true
+ } {
+ string PDFfile exch readstring pop
+ dup (%%EOF\n) eq exch dup (%%EOF\r) eq
+ exch dup (%%EOF\r\n) eq exch (%%EOF) eq or or or not
+ } ifelse {
+ ( **** Warning: File has a corrupted %%EOF marker, or garbage after %%EOF.\n)
+ pdfformaterror
+ } if
+ PDFfile exch setfileposition
+ % Now read the startxref and xref start position.
+ prevline token not { null } if dup type /integertype eq {
+ exch pop cvi % xref start position
+ exch PDFfile exch setfileposition
+ prevline dup (startxref) linene {
+ % startxref not on a line by itself. We have found PDF from
+ % www.verypdf.com in which the startxref was on the same line as
+ % the end of trailer dictionary. Check for this. Note: This
+ % violates the spec.
+ dup (startxref) search {
+ % found startxref - print warning
+ pop pop pop % clear strings from search
+ ( **** Warning: format of the startxref line in this file is invalid.\n)
+ pdfformaterror
+ } { % no startxref - we have a problem.
+ /findxref cvx /syntaxerror signalerror
+ } ifelse
+ } if
+ pop pop
+ } { % else, this file has 'startxref #####' format
+ (startxref) ne { /findxref cvx /syntaxerror signalerror } if
+ cvi % xref start position
+ ( **** Warning: format of the startxref line in this file is invalid.\n)
+ pdfformaterror
+ exch PDFfile exch setfileposition
+ } ifelse
+} bind def
+/stderrfile (%stderr) (w) file def
+/stderrprint { % <string> stderrprint -
+ //stderrfile dup 3 -1 roll writestring flushfile
+} bind def
+/pdfformaterror { % <string> pdfformaterror -
+ stderrprint
+ /Repaired true store
+} 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 TTFWarnList is the list of all TrueType fonts that were not embedded.
+% The UndefProcList collects noisy warnings.
+% This gets rid of many multiple warnings from pdf_font.ps
+/printCollectedWarnings {
+ TTFWarnList length 0 gt {
+ (\n **** Warning: Fonts with Subtype = /TrueType should be embedded.\n)
+ stderrprint
+ ( The following fonts were not embedded:\n)
+ stderrprint
+ [ TTFWarnList { pop .namestring (\t\t\t) exch concatstrings (\n) concatstrings } forall ]
+ { lt } .sort { stderrprint } forall
+ } if
+ 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 {
+ printCollectedWarnings
+ (\n **** This file had errors that were repaired or ignored.\n)
+ stderrprint
+ printProducer
+ ( **** Please notify the author of the software that produced this\n)
+ stderrprint
+ ( **** file that it does not conform to Adobe's published PDF\n)
+ stderrprint
+ ( **** specification.\n\n)
+ stderrprint
+} 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 { linkdest } stopped
+ {
+ cleartomark % ignore this link
+ ( **** Warning: Outline has invalid link that was discarded.\n)
+ pdfformaterror
+ } {
+ /Title oget /Title exch /OUT pdfmark
+ }
+ 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 }
+ { pop false }
+ 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
+ } {
+ exch /Resources pget {
+ exch knownoget { exch knownoget } { pop false } ifelse
+ } {
+ pop pop false
+ } ifelse
+ } ifelse
+} bind def
+
+% Get the total number of pages in the document.
+/pdfpagecount % - pdfpagecount <int>
+ { Trailer /Root oget /Pages oget /Count oget
+ } 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 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
+ % 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>
+{
+ 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
+
+/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
+/linkdest { % <link|outline> linkdest
+ % ([/Page <n>] /View <view> | ) <link|outline>
+ dup /Dest knownoget
+ { resolvedest
+ dup type /dicttype eq { /D knownoget not { null } if } if
+ dup null eq
+ { pop }
+ { dup 0 oget
+ dup type /dicttype eq {
+ dup /Type knownoget {
+ /Page eq {
+ pdfpagenumber
+ } if
+ } if
+ } if
+ dup type /integertype ne
+ { pop }
+ { /Page exch 4 -2 roll }
+ ifelse
+ dup length 1 sub 1 exch getinterval /View exch 3 -1 roll
+ }
+ ifelse
+ }
+ if
+} bind def
+% <pagedict> mark ... -proc- -
+/namedactions 8 dict dup begin
+ /FirstPage {
+ /Page 1 3 -1 roll
+ } def
+ /LastPage {
+ counttomark 2 add index pdfpagecount /Page exch 3 -1 roll
+ } def
+ /NextPage {
+ counttomark 2 add index pdfpagenumber 1 add /Page exch 3 -1 roll
+ } def
+ /PrevPage {
+ counttomark 2 add index pdfpagenumber 1 sub /Page exch 3 -1 roll
+ } def
+end readonly def
+% <pagedict> <annotdict> -proc- -
+/annottypes 5 dict dup begin
+ /Text {
+ mark exch
+ { /Rect /Open /Contents }
+ { 2 copy knownoget { 3 -1 roll } { pop } ifelse }
+ forall pop /ANN pdfmark
+ } bind def
+ /Link {
+ mark exch
+ dup /C knownoget { /Color exch 3 -1 roll } if
+ { /Rect /Border }
+ { 2 copy knownoget { 3 -1 roll } { pop } ifelse }
+ forall dup /A knownoget {
+ dup /URI known {
+ /A mark 3 2 roll % <<>> /A [ <<action>>
+ { oforce } forall
+ .dicttomark
+ 3 2 roll
+ } {
+ dup /D knownoget {
+ exch pop exch dup length dict copy dup /Dest 4 -1 roll put
+ } {
+ /N knownoget { % Assume /S /Named
+ namedactions exch .knownget { exec } if
+ } if
+ } ifelse
+ } ifelse
+ } if
+ linkdest pop /LNK pdfmark
+ } 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
+ pdfshowpage_setpage
+ pdfshowpage_finish
+ } bind def
+
+/pdfpagecontents % <pagedict> pdfpagecontents <contents>
+ { } bind def
+
+/pdfshowpage_init % <pagedict> pdfshowpage_init <pagedict>
+ { /DSCPageCount DSCPageCount 1 add store
+ } bind def
+
+/.pdfshowpage_Install { % <pagedict> [<prevproc>] .pdfshowpage_Install -
+ exch
+ % We would like to clip to the CropBox here, but the subsequent
+ % initgraphics would override it. Instead, we have to handle it
+ % in graphicsbeginpage.
+ dup /CropBox pget dup {exch pop} if systemdict /UseCropBox known and {
+ dup /CropBox pget pop
+ } {
+ dup /MediaBox pget pop % There has to be a MediaBox
+ } ifelse
+ % stack: [<prevproc>] <pagedict> <Crop|Media Box>
+ exch pop oforce_array normrect % done with the pagedict
+ systemdict /PDFFitPage known {
+ PDFDEBUG { (Fiting PDF to imageable area of the page.) = flush } if
+ currentpagedevice /.HWMargins get aload pop
+ currentpagedevice /PageSize get aload pop
+ 3 -1 roll sub 3 1 roll exch sub exch
+ % stack: [<prevproc>] <pagedict> <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: [Box] XImageable YImageable
+ 2 index aload pop 2 index sub exch 3 index sub exch 4 2 roll pop pop
+ % stack: [Box] XImageable YImageable XBox YBox
+ 3 -1 roll exch div 3 1 roll div .min
+ PDFDEBUG { ( Scale by ) print dup = flush } if
+ dup scale
+ } if
+ % Now translate to the origin given in the Crop|Media Box
+ dup 0 get neg exch 1 get neg translate
+ 0 get
+ exec
+} bind def
+
+/pdfshowpage_setpage { % <pagedict> pdfshowpage_setpage <pagedict>
+ 5 dict begin % for setpagedevice
+ % Stack: pagedict
+ % UseCIEColor is always true for PDF; see the comment in runpdf above
+ /UseCIEColor true def
+ currentpagedevice /Orientation 2 index /Rotate pget not { 0 } if 90 idiv
+ % Rotate specifies *clockwise* rotation!
+ neg 3 and def
+ % Stack: pagedict currentpagedict
+ 1 index /CropBox pget dup {exch pop} if systemdict /UseCropBox known and {
+ % Set the page size.
+ 1 index /CropBox pget pop oforce_elems normrect_elems boxrect
+ 2 array astore /PageSize exch def pop pop
+ } {
+ 1 index /MediaBox pget {
+ % Set the page size.
+ oforce_elems normrect_elems boxrect
+ 2 array astore /PageSize exch def pop pop
+ } if
+ } ifelse
+ % Don't change the page size if we are going to fit the PDF to the page
+ systemdict /PDFFitPage known { currentdict /PageSize undef } 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
+
+/pdfshowpage_finish { % <pagedict> pdfshowpage_finish -
+ save /PDFSave exch store
+ /PDFdictstackcount countdictstack store
+ (before exec) VMDEBUG
+
+ % set up color space substitution (this must be inside the page save)
+ pdfshowpage_setcspacesub
+
+ .writepdfmarks {
+
+ % Copy the crop box.
+ dup /CropBox knownoget {
+ oforce_array normrect
+
+ % .pdfshowpage_Install translates the origin -
+ % do same here with the CropBox.
+
+ 1 index /CropBox pget dup {exch pop} if systemdict /UseCropBox known and {
+ 1 index /CropBox pget pop
+ } {
+ 1 index /MediaBox pget pop % There has to be a MediaBox
+ } ifelse
+ oforce_array normrect
+ dup 0 get exch 1 get % [] tx ty
+ 2 index 0 get 2 index sub 3 index exch 0 exch put
+ 2 index 2 get 2 index sub 3 index exch 2 exch put
+ 2 index 1 get 1 index sub 3 index exch 1 exch put
+ 2 index 3 get 1 index sub 3 index exch 3 exch put
+ pop pop
+
+ % If the page has been rotated, rotate the CropBox.
+ mark /CropBox 3 -1 roll
+ 3 index /Rotate pget {
+ 90 idiv 1 and 0 ne {
+ aload pop 4 -2 roll exch 4 2 roll exch 4 array astore
+ } if
+ } if
+ /PAGE pdfmark
+ } if
+
+ % Copy annotations and links.
+ dup /Annots knownoget {
+ 0 1 2 index length 1 sub
+ { 1 index exch oget
+ dup /Subtype oget annottypes exch .knownget { exec } { pop } ifelse
+ }
+ for pop
+ } if
+
+ } if % end .writepdfmarks
+
+ % Display the actual page contents.
+ 6 dict begin
+ /BXlevel 0 def
+ /BGDefault currentblackgeneration def
+ /UCRDefault currentundercolorremoval def
+ %****** DOESN'T HANDLE COLOR TRANSFER YET ******
+ /TRDefault currenttransfer def
+ matrix currentmatrix 2 dict
+ 2 index /CropBox knownoget {
+ oforce_elems normrect_elems boxrect
+ 4 array astore 1 index /ClipRect 3 -1 roll put
+ } if
+ dictbeginpage setmatrix
+ /DefaultQstate qstate store
+
+ dup % for showing annotations below
+ count 1 sub /pdfemptycount exch store
+ % If the page uses any transparency features, show it within
+ % a transparency group.
+ dup pageusestransparency dup /PDFusingtransparency exch def {
+ % 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 knownoget not {
+ 1 index /MediaBox pget pop
+ } if oforce_array normrect .beginformgroup {
+ showpagecontents
+ } stopped {
+ .discardtransparencygroup stop
+ } if .endtransparencygroup
+ } {
+ showpagecontents
+ } ifelse
+ } stopped {
+ % todo: discard
+ .poppdf14devicefilter
+ /DefaultQstate qstate store % device has changed -- reset DefaultQstate
+ stop
+ } if .poppdf14devicefilter
+ /DefaultQstate qstate store % device has changed -- reset DefaultQstate
+ } {
+ showpagecontents
+ } ifelse
+ % check for extra garbage on the ostack and clean it up
+ count pdfemptycount sub dup 0 ne {
+ ( **** File did not complete the page properly and may be damaged.\n)
+ pdfformaterror
+ { pop } repeat
+ } {
+ pop
+ } ifelse
+ % todo: mixing drawing ops outside the device filter could cause
+ % problems, for example with the pnga device.
+ /Annots knownoget { { oforce drawannot } forall } if
+ 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
+ countdictstack PDFdictstackcount sub dup 0 ne {
+ ( **** Warning: File has imbalanced q/Q operators \(too many q's\)\n)
+ pdfformaterror
+ { end } repeat
+ } {
+ pop
+ } ifelse
+ (after exec) VMDEBUG
+ Repaired % pass Repaired state around the restore
+ PDFSave restore
+ /Repaired exch def
+} bind def
+/showpagecontents { % <pagedict> showpagecontents -
+ gsave % preserve gstate for Annotations later
+ /Contents knownoget not { 0 array } if
+ dup type /arraytype ne { 1 array astore } if {
+ oforce false resolvestream pdfopdict .pdfrun
+ } forall
+ grestore
+} 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 ------ %
+
+% Define minimum PDF version for checking for transparency features.
+% Transparency is a 1.4 feature however we have seen files that claimed
+% to be PDF 1.3 with transparency features.
+/PDFtransparencyversion 1.3 def
+
+% 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.
+/pageusestransparency { % <pagedict> pageusestransparency <bool>
+ PDFversion PDFtransparencyversion lt NOTRANSPARENCY or {
+ pop false
+ } {
+ false exch {
+ 4 dict 1 index resourceusestransparency { pop not exit } if
+ /Parent knownoget not { exit } if
+ } 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 known {
+ ( **** File has circular references in resource dictionaries.\n)
+ pdfformaterror
+ pop false exit
+ } if
+ 2 copy dup put
+ dup /ExtGState knownoget {
+ false exch {
+ exch pop oforce
+ 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
+ } forall { pop true exit } if
+ } if
+ dup /XObject knownoget {
+ false exch {
+ exch pop oforce dup /Subtype get
+ dup /Image eq { 1 index /SMask known { pop pop not exit } if } if
+ /Form eq {
+ 3 index exch resourceusestransparency { not exit } if
+ } {
+ pop
+ } ifelse
+ } forall { pop true exit } if
+ } if
+ pop false exit
+ } loop
+ exch pop
+} bind def
+
+% ------ ColorSpace substitution support ------ %
+
+%
+% <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 pseudo-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 /DefaultRGB /DefaultCMYK }
+ {
+ dup 3 index /ColorSpace //rget exec
+ { resolvecolorspace /ColorSpace defineresource pop }
+ { pop }
+ ifelse
+ }
+ forall
+
+ % 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 or
+ { /Pattern setcolorspace setcolorspace }
+ { pop }
+ ifelse
+ }
+ { pop }
+ if
+ }
+ if
+ }
+bind def
+
+
+
+end % pdfdict
+.setglobal