home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World 2000 August
/
PCWorld_2000-08_cd.bin
/
Software
/
TemaCD
/
ghostscr
/
gs601w32.exe
/
gs6.01
/
lib
/
pdf_main.ps
< prev
next >
Wrap
Text File
|
2000-03-09
|
18KB
|
587 lines
% Copyright (C) 1994, 2000 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.
% $Id: pdf_main.ps,v 1.2 2000/03/10 03:56:11 lpd 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
% 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
/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
/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
(.) = 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 growPDFobjects
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
count /pdfemptycount exch def
PDFfile traileropdict .pdfrun
} bind def
% Open a PDF file and read the header, trailer, and cross-reference.
/pdfopen % <file> pdfopen <dict>
{ pdfdict readonly pop % can't do it any earlier than this
15 dict begin
/LocalResources 0 dict def
/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 cvr /PDFversion exch def
findxref
initPDFobjects
% 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
% Copy bookmarks (outline) to the output.
Trailer /Root oget /Outlines knownoget
{ /First knownoget
{ { dup writeoutline /Next knownoget not { exit } if } loop } if
}
if
currentdict end
} bind def
% Skip backward over the %%EOF at the end of the PDF file, and read
% the preceding startxref line. We put this in a separate procedure so
% we can offer the option of accepting certain invalid files that Acrobat
% Reader also accepts.
% ****** NOTE: this will be changed in a future release so that %%EO
% ****** (missing the F), and startxref followed by a blank rather than
% ****** an EOL, will no longer be accepted.
/findxref { % - findxref <xrefpos>
PDFfile dup dup 0 setfileposition bytesavailable {
% Scan backwards over trailing control-character garbage
% (nulls, ^Zs, EOLs, blanks).
1 sub 2 copy setfileposition 1 index read pop
32 gt {exit} if
} loop
% Stack: file endpos
% The top of the stack is now the file position of the last
% non-garbage character.
% We can't use prevline to check for the %%EOF, because if the
% %%EOF isn't followed by an EOL, prevline will read past the
% end of the file, and the file will get closed.
% Acrobat apparently accepts files in which the %%EOF was
% truncated to %%EO (!); we do the same.
5 sub 2 copy setfileposition
1 index (xxxxxx) readstring pop
(\015%%EO) anchorsearch { pop pop } {
(\012%%EO) anchorsearch { pop pop } {
pop findxreferror
} ifelse
} ifelse
1 add setfileposition
% Now read the startxref and xref start position.
prevline token pop dup type /integertype eq {
exch pop cvi % xref start position
exch PDFfile exch setfileposition
prevline (startxref) linene { findxreferror } if
pop
} { % else, this file has 'startxref #####' format
(startxref) ne { findxreferror } if
cvi % xref start position
exch PDFfile exch setfileposition
} ifelse
} bind def
/findxreferror {
(\n) =
( **** The PDF input file appears to be corrupted, or not a PDF file.) =
( **** Try preceding the input file with lib/pdfeof.ps.) =
( **** If the file then is processed without error, please notify the) =
( **** author of the software that produced the PDF file that the file) =
( **** does not conform to Adobe's published PDF specification.) =
(\n) = flush
/pdfopen cvx /syntaxerror signalerror
} 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
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.
/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
/resolvedest { % <name|string|other> resolvedest <other|null>
dup type /nametype eq {
Trailer /Root oget /Dests knownoget {
exch knownoget not { null } if
} {
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 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
% <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
{ /Rect /Border }
{ 2 copy knownoget { 3 -1 roll } { pop } ifelse }
forall dup /A knownoget {
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
} if
linkdest pop /LNK pdfmark
} bind def
end readonly 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>
{ /DSCPageCount DSCPageCount 1 add store
} bind def
/.pdfshowpage_Install { % <tx> <ty> [<prevproc>] .pdfshowpage_Install -
3 1 roll translate 0 get exec
} bind def
/pdfshowpage_setpage { % <pagedict> pdfshowpage_setpage <pagedict>
4 dict begin % for setpagedevice
% Stack: pagedict
% 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 dup /OutputFile known not {
/Orientation 2 index /Rotate pget not { 0 } if 90 idiv
% Rotate specifies *clockwise* rotation!
neg 3 and def
} if
% Stack: pagedict currentpagedict
1 index /MediaBox pget {
% Set the page size.
boxrect [ 2 index 2 index ]
% Stack: pagedict currentpagedict llx lly width height pagesize
/PageSize exch def
% Set the offset on the page.
% Stack: pagedict currentpagedict llx lly width height
% Make the page offset values reals to simplify the
% testing of the Install procedure below.
pop pop exch 0.0 exch sub exch 0.0 exch sub
% Stack: pagedict currentpagedict -llx -lly
[ 3 1 roll 3 index /Install .knownget {
% Don't let the Install procedure get more deeply
% nested after every page.
dup type /arraytype eq {
dup length 5 eq {
dup 3 get /.pdfshowpage_Install load eq {
% Stack: mark tx ty [oldtx oldty [oldproc] .pdfshowpage_Install exec]
aload pop pop pop
5 2 roll 3 -1 roll add
% Stack: mark oldty [oldproc] ty newtx
exch 4 -1 roll add
% Stack: mark [oldproc] newtx newty
3 -1 roll 0 get
} if
} if
} if
1 array astore /.pdfshowpage_Install load /exec load
} {
/translate load
} ifelse ] cvx
% Stack: pagedict currentpagedict installproc
/Install exch def
} if
% Stack: pagedict currentpagedict
pop currentdict end setpagedevice
} 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.
6 dict begin
/BXlevel 0 def
/BGDefault currentblackgeneration def
/UCRDefault currentundercolorremoval def
%****** DOESN'T HANDLE COLOR TRANSFER YET ******
/TRDefault currenttransfer def
matrix currentmatrix beginpage setmatrix
dup /Contents knownoget not { 0 array } if
dup type /arraytype ne { 1 array astore } if
count 1 sub /pdfemptycount exch store
{ oforce false resolvestream pdfopdict .pdfrun
} forall
/Annots knownoget { { oforce drawannot } forall } if
endpage
end % scratch dict
} bind def
end % pdfdict
.setglobal