13508a99a8
rebuilding the xref table does not work for pdfs with compressed object streams. as a work arround, we skip xref table verification and ignore wrong xref gen # for gen 0 objects.
1339 lines
44 KiB
PostScript
1339 lines
44 KiB
PostScript
% 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
|
|
|
|
/NoVerifyXref true 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
|