home *** CD-ROM | disk | FTP | other *** search
/ swCHIP 1991 January / swCHIP_95-1.bin / utility / gs333ini / gs3.33 / pdf_main.ps < prev    next >
Text File  |  1995-12-09  |  11KB  |  371 lines

  1. %    Copyright (C) 1994, 1995 Aladdin Enterprises.  All rights reserved.
  2.  
  3. % pdf_main.ps
  4. % PDF file- and page-level operations.
  5.  
  6. % We don't handle the following PDF elements yet (identified by
  7. % page number in the reference manual):
  8. %    Rotate (53)
  9.  
  10. % We do handle the following as yet undocumented PDF 1.1 extensions:
  11. %
  12. %    - The Dest element of a link or outline entry can be a name,
  13. %    in which case it is looked up in the (optional) Dests dictionary
  14. %    that can appear as an element of the Catalog.
  15. %
  16. %    - The page identifier in a link Dest element can be null, meaning
  17. %    the same page as the link itself appears on.
  18.  
  19. /.setlanguagelevel where { pop 2 .setlanguagelevel } if
  20. .currentglobal true .setglobal
  21. /pdfdict where { pop } { /pdfdict 100 dict def } ifelse
  22. pdfdict begin
  23.  
  24. % For simplicity, we use a single interpretation dictionary for all
  25. % PDF graphics execution, even though this is too liberal.
  26. /pdfopdict mark
  27.   objopdict { } forall
  28.   drawopdict { } forall
  29.   /endstream { exit } bind
  30.   (%%EOF) cvn { exit } bind        % for filters
  31. .dicttomark readonly def
  32.  
  33. % ======================== Main program ======================== %
  34.  
  35. end            % pdfdict
  36. userdict begin
  37.  
  38. /defaultfontname /Times-Roman def
  39.  
  40. % Make sure the registered encodings are loaded, so we don't run the risk
  41. % that some of the indices for their names will overflow the packed
  42. % representation.  (Yes, this is a hack.)
  43. SymbolEncoding pop
  44. DingbatsEncoding pop
  45.  
  46. % Redefine 'run' so it recognizes PDF files.
  47. systemdict begin
  48. /runps /run load def
  49. /run
  50.  { dup type /filetype ne { (r) file } if
  51.    dup read
  52.     { dup (%) 0 get eq
  53.        { pop dup =string readline pop
  54.      (PDF-) anchorsearch
  55.       { pop pop runpdf }
  56.       { pop cvx exec }
  57.      ifelse
  58.        }
  59.        { 2 copy unread pop cvx exec
  60.        }
  61.       ifelse
  62.     }
  63.     { closefile
  64.     }
  65.    ifelse
  66.  } bind odef
  67. /runpdf            % <file> runpdf -
  68.  { userdict begin
  69.    /PSFile where { pop PSFile (w) file /PSout exch def } if
  70.    /Page# null def
  71.    /Page null def
  72.    /PDFSave null def
  73.    GS_PDF_ProcSet begin
  74.    pdfdict begin
  75.    pdfopen begin
  76.    Trailer /Root oget /Pages oget /CropBox knownoget
  77.     { mark /CropBox 3 -1 roll /PAGES pdfmark
  78.     }
  79.    if
  80.    /FirstPage where { pop FirstPage } { 1 } ifelse
  81.    1
  82.    /LastPage where { pop LastPage } { pdfpagecount } ifelse
  83.    QUIET not
  84.     { (Processing pages ) print 2 index =only ( through ) print dup =only
  85.       (.\n) print flush
  86.     }
  87.    if
  88.     { dup /Page# exch store
  89.       QUIET not { (Page ) print dup == flush } if
  90.       [ (%%Page: ) 2 index ( ) 1 index #dsc
  91.       pdfgetpage /Page exch store
  92.       save /PDFSave exch store
  93.       (before exec) VMDEBUG
  94.          Page pdfshowpage
  95.       (after exec) VMDEBUG
  96.       PDFSave restore
  97.     } for
  98.    currentdict pdfclose
  99.    end
  100.    end
  101.    end
  102.  } bind def
  103. % Rebind procedures that invoke 'run'.
  104. /runlibfile
  105.     { findlibfile dup pop
  106.        { exch pop run }
  107.        { /undefinedfilename signalerror }
  108.       ifelse
  109.     } bind def
  110. /.runlibfile /runlibfile load def
  111. end            % systemdict
  112.  
  113. end            % userdict
  114. pdfdict begin
  115.  
  116. % ======================== File parsing ======================== %
  117.  
  118. % Read the cross-reference and trailer sections.
  119.  
  120. /traileropdict mark
  121.   (<<) cvn { mark } bind
  122.   (>>) cvn /.dicttomark load
  123.   /[ { mark } bind        % ditto
  124.   /] /] load
  125.   /true true
  126.   /false false
  127.   /null null
  128.   /R { /resolveR cvx 3 packedarray cvx } bind    % see Objects below
  129.   /startxref /exit load
  130. .dicttomark readonly def
  131.  
  132. % Because of EOL conversion, lines with fixed contents might be followed
  133. % by one or more blanks.
  134. /lineeq            % <filestr> <conststr> lineeq <bool>
  135.  { anchorsearch
  136.     { pop { ( ) anchorsearch not { () eq exit } if pop } loop }
  137.     { pop false }
  138.    ifelse
  139.  } bind def
  140. /linene { lineeq not } bind def
  141.  
  142. % Read (mostly scan) the cross-reference table.
  143. /readxref        % <pos> readxref <trailerdict>
  144.  { PDFfile exch setfileposition
  145.    PDFfile pdfstring readline pop
  146.    (xref) linene { /readxref cvx /syntaxerror signalerror } if
  147.         % Store the xref table entry position for each object.
  148.         % We only need to read the run headers, not every entry.
  149.     { PDFfile pdfstring readline pop
  150.       dup (trailer) lineeq { pop exit } if
  151.       token pop            % first object #
  152.       exch token pop        % entry count
  153.       exch pop exch
  154.             % Stack: count obj#
  155.       PDFfile fileposition 3 -1 roll
  156.        { Objects 2 index get null eq    % later update might have set it
  157.       { Objects 2 index 2 index cvx put }
  158.          if exch 1 add exch 20 add
  159.        }
  160.       repeat PDFfile exch setfileposition pop
  161.     } loop
  162.    PDFfile traileropdict pdfrun
  163.  } bind def
  164.  
  165. % Open a PDF file and read the trailer and cross-reference.
  166. /pdfopen        % <file> pdfopen <dict>
  167.  { 10 dict begin
  168.    cvlit /PDFfile exch def
  169.    /PDFsource PDFfile def
  170.    PDFfile dup dup 0 setfileposition bytesavailable setfileposition
  171.    prevline (%%EOF) linene { /pdfopen cvx /syntaxerror signalerror } if
  172.    PDFfile exch setfileposition
  173.    prevline cvi        % xref start position
  174.    exch PDFfile exch setfileposition
  175.    prevline (startxref) linene { /pdfopen cvx /syntaxerror signalerror } if
  176.     % Scan backwards for the start of the trailer,
  177.     % since we have to read the trailer before the first xref section.
  178.     { PDFfile exch setfileposition
  179.       prevline (trailer) lineeq { exit } if
  180.     }
  181.    loop pop PDFfile traileropdict pdfrun
  182.         % Stack: xrefpos trailerdict
  183.    /Trailer exch def
  184.    Trailer /Size get
  185.    /Objects 1 index array def
  186.    /Generations exch string def
  187.     % Read the last cross-reference table.
  188.    readxref pop
  189.     % Read any previous cross-reference tables.
  190.    Trailer { /Prev .knownget not { exit } if readxref } loop
  191.     % Create and initialize some caches.
  192.    /PageCount pdfpagecount def
  193.    /PageNumbers PageCount dict def
  194.     % Write the DSC header if appropriate.
  195.    [ (%!PS-Adobe-1.0) #dsc
  196.    [ (%%Pages: ) pdfpagecount #dsc
  197.    [ (%%EndComments) #dsc
  198.    [ (%%BeginProlog) #dsc
  199.    [ (\(gs_pdf.ps\) /runlibfile where { pop runlibfile } { run } ifelse) #dsc
  200.    [ (GS_PDF_ProcSet begin) #dsc
  201.    [ (%%EndProlog) #dsc
  202.     % Copy bookmarks (outline) to the output.
  203.    Trailer /Root oget /Outlines knownoget
  204.     { /First knownoget
  205.        { { dup writeoutline /Next knownoget not { exit } if } loop }
  206.       if
  207.     }
  208.    if   
  209.    currentdict end
  210.  } bind def
  211.  
  212. % Write the outline structure for a file.  Uses linkdest (below).
  213. /writeoutline        % <outlinedict> writeoutline -
  214.  { mark
  215.    0 2 index /First knownoget
  216.     { { exch 1 add exch /Next knownoget not { exit } if } loop }
  217.    if
  218.         % stack: dict mark count
  219.    dup 0 eq
  220.     { pop 1 index
  221.     }
  222.     { 2 index /Count knownoget { 0 lt { neg } if } if
  223.       /Count exch 3 index
  224.     }
  225.    ifelse linkdest /Title oget /Title exch /OUT pdfmark
  226.    /First knownoget
  227.     { { dup writeoutline /Next knownoget not { exit } if } loop }
  228.    if
  229.  } bind def
  230.  
  231. % Close a PDF file.
  232. /pdfclose        % <dict> pdfclose -
  233.  { begin
  234.    /PSout where { pop [ (%%Trailer) #dsc PSout closefile } if
  235.    PDFfile closefile
  236.    end
  237.  } bind def
  238.  
  239. % ======================== Page accessing ======================== %
  240.  
  241. % Get a (possibly inherited) attribute of a page.
  242. /pget            % <pagedict> <key> pget <value> -true-
  243.             % <pagedict> <key> pget -false-
  244.  { 2 copy knownoget
  245.     { exch pop exch pop true
  246.     }
  247.     { exch /Parent knownoget
  248.        { exch pget }
  249.        { pop false }
  250.       ifelse
  251.     }
  252.    ifelse
  253.  } bind def
  254.  
  255. % Get the total number of pages in the document.
  256. /pdfpagecount        % - pdfpagecount <int>
  257.  { Trailer /Root oget /Pages oget /Count oget
  258.  } bind def
  259.  
  260. % Get the N'th page of the document.
  261. % The first page is numbered 1.
  262. /pdfgetpage        % <int> pdfgetpage <pagedict>
  263.  { dup Trailer /Root oget /Pages oget
  264.     {        % We should be able to tell when we reach a leaf
  265.         % by finding a Type unequal to /Pages.  Unfortunately,
  266.         % some files distributed by Adobe lack the Type key
  267.         % in some of the Pages nodes!  Instead, we check for Kids.
  268.       dup /Kids knownoget not { exit } if
  269.       exch pop null
  270.       0 1 3 index length 1 sub
  271.        { 2 index exch oget
  272.      dup /Kids known { dup /Count oget } { 1 } ifelse
  273.         % Stack: index kids null node count
  274.      dup 5 index ge { pop exch pop exit } if
  275.      5 -1 roll exch sub 4 1 roll pop
  276.        }
  277.       for exch pop
  278.       dup null eq { pop pop 1 null exit } if
  279.     }
  280.    loop
  281.    1 index 1 ne { pop pop /pdfgetpage cvx /rangecheck signalerror } if
  282.    exch pop exch pop
  283.  } bind def
  284.  
  285. % Find the page number of a page object (inverse of pdfgetpage).
  286. /pdfpagenumber        % <pagedict> pdfpagenumber <int>
  287.  {    % We use the simplest and stupidest of all possible algorithms....
  288.    PageNumbers 1 index .knownget
  289.     { exch pop
  290.     }
  291.     { 1 1 PageCount 1 add    % will give a rangecheck if not found
  292.        { dup pdfgetpage oforce 2 index eq { exit } if pop
  293.        }
  294.       for
  295.       PageNumbers 3 -1 roll 2 index put
  296.     }
  297.    ifelse
  298.  } bind def
  299.  
  300. % Display a given page.
  301. /boxrect        % [<llx> <lly> <urx> <ury>] boxrect <x> <y> <w> <h>
  302.  { aload pop exch 3 index sub exch 2 index sub
  303.  } bind def
  304. /linkdest        % <link|outline> linkdest
  305.             %   ([/Page <n>] /View <view> | ) <link|outline>
  306.  { dup /Dest knownoget
  307.     {        % Check for a name, to be looked up in Dests.
  308.       dup type /nametype eq
  309.        { Trailer /Root oget /Dests oget exch oget /D get }
  310.       if
  311.       dup 0 oget
  312.       dup null eq
  313.        { pop }
  314.        { pdfpagenumber 1 add /Page exch 4 -2 roll }
  315.       ifelse
  316.       dup length 1 sub 1 exch getinterval /View exch 3 -1 roll
  317.     }
  318.    if
  319.  } bind def
  320. /annottypes 5 dict dup begin
  321.   /Text
  322.     { mark exch
  323.        { /Rect /Open /Contents }
  324.        { 2 copy knownoget { 3 -1 roll } { pop } ifelse }
  325.       forall pop /ANN pdfmark
  326.     } bind def
  327.   /Link
  328.     { mark exch
  329.        { /Rect /Border }
  330.        { 2 copy knownoget { 3 -1 roll } { pop } ifelse }
  331.       forall linkdest pop /LNK pdfmark
  332.     } bind def
  333. end def
  334. /pdfshowpage        % <pagedict> pdfshowpage -
  335.  { dup /Contents knownoget not { 0 array } if
  336.    dup type /arraytype ne { 1 array astore } if
  337.    gsave
  338.    1 index /MediaBox pget
  339.     {        % We should really use setpagedevice to set the page size,
  340.         % but it doesn't work reliably yet.
  341.       boxrect statusdict /.setpagesize get exec
  342.       exch neg exch neg translate
  343.     }
  344.     { initmatrix initclip
  345.     }
  346.    ifelse
  347.    1 index /CropBox pget
  348.     { boxrect rectclip
  349.       1 index /CropBox knownoget { mark /CropBox 3 -1 roll /PAGE pdfmark } if
  350.     }
  351.    if
  352.     % Copy annotations and links.
  353.    1 index /Annots knownoget
  354.     { 0 1 2 index length 1 sub
  355.        { 1 index exch oget
  356.          dup /Subtype oget annottypes exch .knownget { exec } { pop } ifelse
  357.        }
  358.       for pop
  359.     }
  360.    if
  361.    exch pop
  362.    beginpage
  363.     { oforce false resolvestream pdfopdict pdfrun } forall
  364.    endpage
  365.    grestore
  366.    /showpage 0 #
  367.  } bind def
  368.  
  369. end            % pdfdict
  370. .setglobal
  371.