home *** CD-ROM | disk | FTP | other *** search
- % Copyright (C) 1994, 1996, 1997 Aladdin Enterprises. All rights reserved.
- %
- % This file is part of Aladdin Ghostscript.
- %
- % Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
- % or distributor accepts any responsibility for the consequences of using it,
- % or for whether it serves any particular purpose or works at all, unless he
- % or she says so in writing. Refer to the Aladdin Ghostscript Free Public
- % License (the "License") for full details.
- %
- % Every copy of Aladdin Ghostscript must include a copy of the License,
- % normally in a plain ASCII text file named PUBLIC. The License grants you
- % the right to copy, modify and redistribute Aladdin Ghostscript, but only
- % under certain conditions described in the License. Among other things, the
- % License requires that the copyright notice and this notice be preserved on
- % all copies.
-
- % pdf_main.ps
- % PDF file- and page-level operations.
-
- % We handle the following PDF 1.2 constructs:
- % page number rather than page object in Dest array
- % We explicitly ignore the following PDF 1.2 constructs:
- % "Marked content" operators
-
- /.setlanguagelevel where { pop 2 .setlanguagelevel } if
- .currentglobal true .setglobal
- /pdfdict where { pop } { /pdfdict 100 dict def } ifelse
- pdfdict begin
-
- % 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
- % 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
- /runpdfstring 50 string def % length is arbitrary
- /run
- { dup type /filetype ne { (r) file } if
- dup read
- { dup (%) 0 get eq
- { pop dup //runpdfstring
- % Some invalid files might have extra-long first lines....
- { { readline } .internalstopped not { pop pop exit } if
- pop =string
- }
- loop
- //runpdfstring (PDF-) anchorsearch
- { pop pop runpdf }
- { pop cvx .runexec }
- ifelse
- }
- { 2 copy unread pop .runps
- }
- ifelse
- }
- { closefile
- }
- ifelse
- } bind odef
- /runpdf % <file> runpdf -
- { userdict begin
- /PSFile where { pop PSFile (w) file /PSout exch def } if
- /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
- { mark /CropBox 3 -1 roll /PAGES pdfmark
- }
- if
- /FirstPage where { pop FirstPage } { 1 } ifelse
- 1
- /LastPage where { pop LastPage } { pdfpagecount } ifelse
- QUIET not
- { (Processing pages ) print 2 index =only ( through ) print dup =only
- (.\n) print flush
- }
- if
- { dup /Page# exch store
- QUIET not { (Page ) print dup == flush } if
- pdfgetpage pdfshowpage
- } for
- currentdict pdfclose
- end % temporary dict
- end % pdfdict
- end % userdict
- } 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 load
- ([) cvn { mark } bind % ditto
- (]) cvn dup load
- /true true
- /false false
- /null null
- /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 (mostly scan) the cross-reference table.
- /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
- PDFfile exch setfileposition
- PDFfile pdfstring readline pop
- (xref) linene { /readxref cvx /syntaxerror signalerror } if
- % Store the xref table entry position for each object.
- % We only need to read the run headers, not every entry.
- { PDFfile token pop % first object # or trailer
- dup /trailer eq { pop exit } if
- PDFfile pdfstring readline pop
- token pop % entry count
- exch pop exch
- % This section might be adding new objects:
- % ensure that Objects and Generations are big enough.
- % Stack: count obj#
- 2 copy add
- dup Objects llength gt
- { dup Objects exch lgrowto /Objects exch def }
- if
- dup Generations llength gt
- { dup Generations exch lgrowto /Generations exch def }
- if
- pop
- PDFfile fileposition 3 -1 roll
- { Objects 2 index lget null eq % later update might have set it
- { Objects 2 index 2 index cvx lput }
- if exch 1 add exch 20 add
- }
- repeat PDFfile exch setfileposition pop
- } loop
- PDFfile traileropdict .pdfrun
- } bind def
-
- % Open a PDF file and read the trailer and cross-reference.
- /pdfopen % <file> pdfopen <dict>
- { pdfdict readonly pop % can't do it any earlier than this
- /PSout where { pop /pdf2psdict where { pop pdf2psdict begin } if } if
- 10 dict begin
- /PSLevel1 where { pop } { /PSLevel1 false def } ifelse
- cvlit /PDFfile exch def
- /PDFsource PDFfile def
- 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 pop
- PDFfile dup dup 0 setfileposition bytesavailable
- % Scan backwards over trailing control-character garbage
- % (nulls, ^Zs, EOLs).
- { 1 sub 2 copy setfileposition 1 index read pop
- 32 ge {exit} if
- } loop 1 sub setfileposition
- prevline (%%EOF) linene { /pdfopen cvx /syntaxerror signalerror } if
- PDFfile exch setfileposition
- prevline cvi % xref start position
- exch PDFfile exch setfileposition
- prevline (startxref) linene { /pdfopen cvx /syntaxerror signalerror } if
- pop
- % Stack: xrefpos
- /Objects larray def
- /Generations lstring def
- % Read the last cross-reference table.
- readxref /Trailer exch def
- Trailer /Encrypt known
- { pdf_process_Encrypt % signal error
- }
- if
- % Read any previous cross-reference tables.
- Trailer { /Prev .knownget not { exit } if readxref } loop
- % Create and initialize some caches.
- /PageCount pdfpagecount def
- /PageNumbers PageCount dict def
- /PageIndex PageCount array def
- % Write the DSC header if appropriate.
- [ (%!PS-Adobe-1.0) #dsc
- [ (%%Pages: (atend)) #dsc
- [ (%%EndComments) #dsc
- [ (%%BeginProlog) #dsc
- [ (% This copyright applies to everything between here and the %%EndProlog:) #dsc
- [ (% ) copyright #dsc
- (gs_pdf.ps) #dscfile
- PSLevel1 { (gs_l2img.ps) #dscfile } if
- [ (%%EndProlog) #dsc
- % Copy bookmarks (outline) to the output.
- #?
- { Trailer /Root oget /Outlines knownoget
- { /First knownoget
- { { dup writeoutline /Next knownoget not { exit } if } loop }
- if
- }
- if
- }
- if
- currentdict end
- } bind def
-
- % Write the outline structure for a file. Uses linkdest (below).
- /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 /Title oget /Title exch /OUT pdfmark
- /First knownoget
- { { dup writeoutline /Next knownoget not { exit } if } loop }
- if
- } bind def
-
- % Close a PDF file.
- /pdfclose % <dict> pdfclose -
- { begin
- /PSout where
- { pop
- [ (%%Trailer) #dsc
- [ (%%Pages: ) DSCPageCount #dsc
- PSout closefile
- }
- if
- PDFfile closefile
- end
- pdf2psdict where { pop currentdict pdf2psdict eq { end } if } if
- } 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-
- { exch /Resources pget
- { exch knownoget
- { exch knownoget }
- { pop false }
- ifelse
- }
- { pop pop false
- }
- 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.
- /pdffindpage % <int> pdffindpage <pagedict>
- { dup Trailer /Root oget /Pages oget
- { % 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 /Kids knownoget not { exit } if
- exch pop null
- 0 1 3 index length 1 sub
- { 2 index exch oget
- dup /Kids known { dup /Count oget } { 1 } ifelse
- % Stack: index kids null node count
- dup 5 index ge { pop exch pop exit } if
- 5 -1 roll exch sub 4 1 roll pop
- }
- for exch pop
- dup null eq { pop pop 1 null exit } if
- }
- loop
- % Stack: index countleft node
- 1 index 1 ne { pop pop /pdffindpage cvx /rangecheck signalerror } if
- exch pop
- PageIndex 2 index 1 sub 2 index put
- PageNumbers 1 index 3 index put
- exch pop
- } 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 get dup null ne
- { exch pop }
- { 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
-
- % Display a given page.
- /boxrect % [<llx> <lly> <urx> <ury>] boxrect <x> <y> <w> <h>
- { aload pop exch 3 index sub exch 2 index sub
- } bind def
- /linkdest % <link|outline> linkdest
- % ([/Page <n>] /View <view> | ) <link|outline>
- { dup /Dest knownoget
- { % Check for a name, to be looked up in Dests.
- dup type /nametype eq
- { Trailer /Root oget /Dests oget exch knownoget
- { dup type /dicttype eq { /D get } if }
- { null }
- ifelse
- }
- if
- dup null eq
- { pop }
- { dup 0 oget
- dup null eq
- { pop }
- { dup type /integertype ne { pdfpagenumber } if
- /Page exch 4 -2 roll
- }
- ifelse
- dup length 1 sub 1 exch getinterval /View exch 3 -1 roll
- }
- ifelse
- }
- if
- } bind def
- /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
- { /Rect /Border }
- { 2 copy knownoget { 3 -1 roll } { pop } ifelse }
- forall linkdest pop /LNK pdfmark
- } bind def
- end def
-
- /pdfshowpage % <pagedict> pdfshowpage -
- { dup /Page exch store
- pdfshowpage_init
- pdfshowpage_setpage
- save /PDFSave exch store
- (before exec) VMDEBUG
- pdfshowpage_finish
- (after exec) VMDEBUG
- PDFSave restore
- } bind def
-
- /pdfpagecontents % <pagedict> pdfpagecontents <contents>
- { } bind def
-
- /pdfshowpage_init % <pagedict> pdfshowpage_init <pagedict>
- { gsave
- [ (%%Page: ) Page# ( )
- DSCPageCount 1 add /DSCPageCount 1 index store #dsc
- [ (GS_PDF_ProcSet begin) #dsc
- } bind def
-
- /pdfshowpage_setpage % <pagedict> pdfshowpage_setpage <pagedict>
- {
- 3 dict % for setpagedevice
- % Stack: pagedict setpagedict
- % We want to look at Rotate for displays, but not for printers.
- % The following is a hack, but we don't know a better way to do this.
- currentpagedevice /OutputFile known
- /PSout where dup { exch pop } if or not
- { dup /Orientation 3 index /Rotate pget not { 0 } if 90 idiv
- % Rotate specifies *clockwise* rotation!
- neg 3 and put
- }
- if
- % Stack: pagedict setpagedict
- 1 index /MediaBox pget
- { % Set the page size.
- boxrect [ 2 index 5 index sub 2 index 5 index sub ]
- % Stack: pagedict setpagedict llx lly urx ury pagesize
- 5 index exch /PageSize exch put
- % Stack: pagedict contents setpagedict llx lly urx ury
- pop pop
- neg exch neg exch
- [ 3 1 roll ]
- % Stack: pagedict setpagedict pageoffset
- 1 index exch /PageOffset exch put
- }
- if
- % Stack: pagedict setpagedict
- /setpagedevice 1 #
- } bind def
-
- /pdfshowpage_finish % <pagedict> pdfshowpage_finish -
- {
- % Copy crop box.
- dup /CropBox pget
- { boxrect rectclip
- dup /CropBox knownoget { mark /CropBox 3 -1 roll /PAGE pdfmark } if
- }
- 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
-
- % Display the actual page contents.
- 2 dict begin
- /BXlevel 0 def
- matrix currentmatrix /beginpage 0 # setmatrix
- /Contents knownoget not { 0 array } if
- dup type /arraytype ne { 1 array astore } if
- { oforce false resolvestream pdfopdict .pdfrun } forall
- /endpage 0 #
- end % scratch dict
- grestore
- [ (end) #dsc
- } bind def
-
- end % pdfdict
- .setglobal
-