home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / APPS / gs403osk.tgz / gs403osk.tar / pdf_main.ps < prev    next >
Text File  |  1996-10-12  |  14KB  |  473 lines

  1. %    Copyright (C) 1994, 1996 Aladdin Enterprises.  All rights reserved.
  2. % This file is part of Aladdin Ghostscript.
  3. % Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  4. % or distributor accepts any responsibility for the consequences of using it,
  5. % or for whether it serves any particular purpose or works at all, unless he
  6. % or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  7. % License (the "License") for full details.
  8. % Every copy of Aladdin Ghostscript must include a copy of the License,
  9. % normally in a plain ASCII text file named PUBLIC.  The License grants you
  10. % the right to copy, modify and redistribute Aladdin Ghostscript, but only
  11. % under certain conditions described in the License.  Among other things, the
  12. % License requires that the copyright notice and this notice be preserved on
  13. % all copies.
  14.  
  15. % pdf_main.ps
  16. % PDF file- and page-level operations.
  17.  
  18. % We handle the following PDF 1.2 constructs:
  19. %   page number rather than page object in Dest array
  20.  
  21. /.setlanguagelevel where { pop 2 .setlanguagelevel } if
  22. .currentglobal true .setglobal
  23. /pdfdict where { pop } { /pdfdict 100 dict def } ifelse
  24. pdfdict begin
  25.  
  26. % For simplicity, we use a single interpretation dictionary for all
  27. % PDF graphics execution, even though this is too liberal.
  28. /pdfopdict mark
  29.   objopdict { } forall
  30.   drawopdict { } forall
  31.   /endstream { exit } bind
  32.   (%%EOF) cvn { exit } bind     % for filters
  33. .dicttomark readonly def
  34.  
  35. % ======================== Main program ======================== %
  36.  
  37. end         % pdfdict
  38. userdict begin
  39.  
  40. /defaultfontname /Times-Roman def
  41.  
  42. % Make sure the registered encodings are loaded, so we don't run the risk
  43. % that some of the indices for their names will overflow the packed
  44. % representation.  (Yes, this is a hack.)
  45. SymbolEncoding pop
  46. DingbatsEncoding pop
  47.  
  48. % Redefine 'run' so it recognizes PDF files.
  49. systemdict begin
  50. /runps /run load def
  51. /runpdfstring 50 string def     % length is arbitrary
  52. /run
  53.  { dup type /filetype ne { (r) file } if
  54.    dup read
  55.     { dup (%) 0 get eq
  56.        { pop dup //runpdfstring
  57.         % Some invalid files might have extra-long first lines....
  58.       {  { readline } .internalstopped not { pop pop exit } if
  59.         pop =string
  60.       }
  61.      loop
  62.      //runpdfstring (PDF-) anchorsearch
  63.       { pop pop runpdf }
  64.       { pop cvx .runexec }
  65.      ifelse
  66.        }
  67.        { 2 copy unread pop cvx .runexec
  68.        }
  69.       ifelse
  70.     }
  71.     { closefile
  72.     }
  73.    ifelse
  74.  } bind odef
  75. /runpdf         % <file> runpdf -
  76.  { userdict begin
  77.    /PSFile where { pop PSFile (w) file /PSout exch def } if
  78.    /Page# null def
  79.    /Page null def
  80.    /DSCPageCount 0 def
  81.    /PDFSave null def
  82.    GS_PDF_ProcSet begin
  83.    pdfdict begin
  84.    pdfopen begin
  85.    Trailer /Root oget /Pages oget /CropBox knownoget
  86.     { mark /CropBox 3 -1 roll /PAGES pdfmark
  87.     }
  88.    if
  89.    /FirstPage where { pop FirstPage } { 1 } ifelse
  90.    1
  91.    /LastPage where { pop LastPage } { pdfpagecount } ifelse
  92.    QUIET not
  93.     { (Processing pages ) print 2 index =only ( through ) print dup =only
  94.       (.\n) print flush
  95.     }
  96.    if
  97.     { dup /Page# exch store
  98.       QUIET not { (Page ) print dup == flush } if
  99.       pdfgetpage pdfshowpage
  100.     } for
  101.    currentdict pdfclose
  102.    end          % temporary dict
  103.    end          % pdfdict
  104.    end          % userdict
  105.  } bind def
  106. % Rebind procedures that invoke 'run'.
  107. % Note that .runstdin will fail if stdin is not seekable.
  108. /runlibfile
  109.     { findlibfile dup pop
  110.        { exch pop run }
  111.        { /undefinedfilename signalerror }
  112.       ifelse
  113.     } bind def
  114. /.runlibfile /runlibfile load def
  115. /.runstdin 
  116.     { (%stdin) (r) file run
  117.     } bind def
  118. end         % systemdict
  119.  
  120. end         % userdict
  121. pdfdict begin
  122.  
  123. % ======================== File parsing ======================== %
  124.  
  125. % Read the cross-reference and trailer sections.
  126.  
  127. /traileropdict mark
  128.   (<<) cvn { mark } bind
  129.   (>>) cvn /.dicttomark load
  130.   ([) cvn { mark } bind     % ditto
  131.   (]) cvn dup load
  132.   /true true
  133.   /false false
  134.   /null null
  135.   /R { /resolveR cvx 3 packedarray cvx } bind   % see Objects below
  136.   /startxref /exit load
  137. .dicttomark readonly def
  138.  
  139. % Because of EOL conversion, lines with fixed contents might be followed
  140. % by one or more blanks.
  141. /lineeq         % <filestr> <conststr> lineeq <bool>
  142.  { anchorsearch
  143.     { pop { ( ) anchorsearch not { () eq exit } if pop } loop }
  144.     { pop false }
  145.    ifelse
  146.  } bind def
  147. /linene { lineeq not } bind def
  148.  
  149. % Read (mostly scan) the cross-reference table.
  150. /readxref       % <pos> readxref <trailerdict>
  151.  { PDFoffset add PDFfile exch setfileposition
  152.    PDFfile pdfstring readline pop
  153.    (xref) linene { /readxref cvx /syntaxerror signalerror } if
  154.         % Store the xref table entry position for each object.
  155.         % We only need to read the run headers, not every entry.
  156.     { PDFfile token pop     % first object # or trailer
  157.       dup /trailer eq { pop exit } if
  158.       PDFfile pdfstring readline pop
  159.       token pop         % entry count
  160.       exch pop exch
  161.         % This section might be adding new objects:
  162.         % ensure that Objects and Generations are big enough.
  163.         % Stack: count obj#
  164.       2 copy add
  165.       dup Objects length gt
  166.        { dup array Objects 1 index copy pop /Objects exch def }
  167.       if
  168.       dup Generations length gt
  169.        { dup string Generations 1 index copy pop /Generations exch def }
  170.       if
  171.       pop
  172.       PDFfile fileposition 3 -1 roll
  173.        { Objects 2 index get null eq    % later update might have set it
  174.       { Objects 2 index 2 index cvx put }
  175.          if exch 1 add exch 20 add
  176.        }
  177.       repeat PDFfile exch setfileposition pop
  178.     } loop
  179.    PDFfile traileropdict .pdfrun
  180.  } bind def
  181.  
  182. % Open a PDF file and read the trailer and cross-reference.
  183. /pdfopen        % <file> pdfopen <dict>
  184.  { pdfdict readonly pop     % can't do it any earlier than this
  185.    /PSout where { pop /pdf2psdict where { pop pdf2psdict begin } if } if
  186.    10 dict begin
  187.    /PSLevel1 where { pop } { /PSLevel1 false def } ifelse
  188.    cvlit /PDFfile exch def
  189.    /PDFsource PDFfile def
  190.    PDFfile dup 0 setfileposition pdfstring readstring 
  191.    not {/pdfopen cvx /syntaxerror signalerror} if
  192.    (%PDF-) search not {/pdfopen cvx /syntaxerror signalerror} if
  193.    length /PDFoffset exch def pop pop
  194.    PDFfile dup dup 0 setfileposition bytesavailable 
  195.     % Scan backwards over trailing control-character garbage
  196.     % (nulls, ^Zs, EOLs).
  197.     { 1 sub 2 copy setfileposition 1 index read pop
  198.       32 ge {exit} if
  199.     } loop 1 sub setfileposition
  200.    prevline (%%EOF) linene { /pdfopen cvx /syntaxerror signalerror } if
  201.    PDFfile exch setfileposition
  202.    prevline cvi     % xref start position
  203.    exch PDFfile exch setfileposition
  204.    prevline (startxref) linene { /pdfopen cvx /syntaxerror signalerror } if
  205.    pop
  206.         % Stack: xrefpos
  207.    /Objects [] def
  208.    /Generations <> def
  209.     % Read the last cross-reference table.
  210.    readxref /Trailer exch def
  211.    Trailer /Encrypt known
  212.     { pdf_process_Encrypt   % signal error
  213.     }
  214.    if
  215.     % Read any previous cross-reference tables.
  216.    Trailer { /Prev .knownget not { exit } if readxref } loop
  217.     % Create and initialize some caches.
  218.    /PageCount pdfpagecount def
  219.    /PageNumbers PageCount dict def
  220.    /PageIndex PageCount array def
  221.     % Write the DSC header if appropriate.
  222.    [ (%!PS-Adobe-1.0) #dsc
  223.    [ (%%Pages: (atend)) #dsc
  224.    [ (%%EndComments) #dsc
  225.    [ (%%BeginProlog) #dsc
  226.    [ (% This copyright applies to everything between here and the %%EndProlog:) #dsc
  227.    [ (% ) copyright #dsc
  228.    (gs_pdf.ps) #dscfile
  229.    PSLevel1 { (gs_l2img.ps) #dscfile } if
  230.    [ (%%EndProlog) #dsc
  231.     % Copy bookmarks (outline) to the output.
  232.    #?
  233.     { Trailer /Root oget /Outlines knownoget
  234.        { /First knownoget
  235.       { { dup writeoutline /Next knownoget not { exit } if } loop }
  236.      if
  237.        }
  238.       if
  239.     }
  240.    if   
  241.    currentdict end
  242.  } bind def
  243.  
  244. % Write the outline structure for a file.  Uses linkdest (below).
  245. /writeoutline       % <outlinedict> writeoutline -
  246.  { mark
  247.    0 2 index /First knownoget
  248.     { { exch 1 add exch /Next knownoget not { exit } if } loop }
  249.    if
  250.         % stack: dict mark count
  251.    dup 0 eq
  252.     { pop 1 index
  253.     }
  254.     { 2 index /Count knownoget { 0 lt { neg } if } if
  255.       /Count exch 3 index
  256.     }
  257.    ifelse linkdest /Title oget /Title exch /OUT pdfmark
  258.    /First knownoget
  259.     { { dup writeoutline /Next knownoget not { exit } if } loop }
  260.    if
  261.  } bind def
  262.  
  263. % Close a PDF file.
  264. /pdfclose       % <dict> pdfclose -
  265.  { begin
  266.    /PSout where
  267.     { pop
  268.       [ (%%Trailer) #dsc
  269.       [ (%%Pages: ) DSCPageCount #dsc
  270.       PSout closefile
  271.     }
  272.    if
  273.    PDFfile closefile
  274.    end
  275.    pdf2psdict where { pop currentdict pdf2psdict eq { end } if } if
  276.  } bind def
  277.  
  278. % ======================== Page accessing ======================== %
  279.  
  280. % Get a (possibly inherited) attribute of a page.
  281. /pget           % <pagedict> <key> pget <value> -true-
  282.             % <pagedict> <key> pget -false-
  283.  { 2 copy knownoget
  284.     { exch pop exch pop true
  285.     }
  286.     { exch /Parent knownoget
  287.        { exch pget }
  288.        { pop false }
  289.       ifelse
  290.     }
  291.    ifelse
  292.  } bind def
  293.  
  294. % Get the total number of pages in the document.
  295. /pdfpagecount       % - pdfpagecount <int>
  296.  { Trailer /Root oget /Pages oget /Count oget
  297.  } bind def
  298.  
  299. % Find the N'th page of the document by iterating through the Pages tree.
  300. % The first page is numbered 1.
  301. /pdffindpage        % <int> pdffindpage <pagedict>
  302.  { dup Trailer /Root oget /Pages oget
  303.     {       % We should be able to tell when we reach a leaf
  304.         % by finding a Type unequal to /Pages.  Unfortunately,
  305.         % some files distributed by Adobe lack the Type key
  306.         % in some of the Pages nodes!  Instead, we check for Kids.
  307.       dup /Kids knownoget not { exit } if
  308.       exch pop null
  309.       0 1 3 index length 1 sub
  310.        { 2 index exch oget
  311.      dup /Kids known { dup /Count oget } { 1 } ifelse
  312.         % Stack: index kids null node count
  313.      dup 5 index ge { pop exch pop exit } if
  314.      5 -1 roll exch sub 4 1 roll pop
  315.        }
  316.       for exch pop
  317.       dup null eq { pop pop 1 null exit } if
  318.     }
  319.    loop
  320.         % Stack: index countleft node
  321.    1 index 1 ne { pop pop /pdffindpage cvx /rangecheck signalerror } if
  322.    exch pop
  323.    PageIndex 2 index 1 sub 2 index put
  324.    PageNumbers 1 index 3 index put
  325.    exch pop
  326.  } bind def
  327.  
  328. % Find the N'th page of the document.
  329. % The first page is numbered 1.
  330. /pdfgetpage     % <int> pdfgetpage <pagedict>
  331.  { PageIndex 1 index 1 sub get dup null ne
  332.     { exch pop }
  333.     { pop pdffindpage }
  334.    ifelse
  335.  } bind def
  336.  
  337. % Find the page number of a page object (inverse of pdfgetpage).
  338. /pdfpagenumber      % <pagedict> pdfpagenumber <int>
  339.  {  % We use the simplest and stupidest of all possible algorithms....
  340.    PageNumbers 1 index .knownget
  341.     { exch pop
  342.     }
  343.     { 1 1 PageCount 1 add   % will give a rangecheck if not found
  344.        { dup pdfgetpage oforce 2 index eq { exit } if pop
  345.        }
  346.       for exch pop
  347.     }
  348.    ifelse
  349.  } bind def
  350.  
  351. % Display a given page.
  352. /boxrect        % [<llx> <lly> <urx> <ury>] boxrect <x> <y> <w> <h>
  353.  { aload pop exch 3 index sub exch 2 index sub
  354.  } bind def
  355. /linkdest       % <link|outline> linkdest
  356.             %   ([/Page <n>] /View <view> | ) <link|outline>
  357.  { dup /Dest knownoget
  358.     {       % Check for a name, to be looked up in Dests.
  359.       dup type /nametype eq
  360.        { Trailer /Root oget /Dests oget exch oget
  361.          dup type /dicttype eq { /D get } if
  362.        }
  363.       if
  364.       dup 0 oget
  365.       dup null eq
  366.        { pop }
  367.        { dup type /integertype ne { pdfpagenumber } if /Page exch 4 -2 roll }
  368.       ifelse
  369.       dup length 1 sub 1 exch getinterval /View exch 3 -1 roll
  370.     }
  371.    if
  372.  } bind def
  373. /annottypes 5 dict dup begin
  374.   /Text
  375.     { mark exch
  376.        { /Rect /Open /Contents }
  377.        { 2 copy knownoget { 3 -1 roll } { pop } ifelse }
  378.       forall pop /ANN pdfmark
  379.     } bind def
  380.   /Link
  381.     { mark exch
  382.        { /Rect /Border }
  383.        { 2 copy knownoget { 3 -1 roll } { pop } ifelse }
  384.       forall linkdest pop /LNK pdfmark
  385.     } bind def
  386. end def
  387.  
  388. /pdfshowpage        % <pagedict> pdfshowpage -
  389.  { dup /Page exch store
  390.    pdfshowpage_init 
  391.    pdfshowpage_setpage 
  392.    save /PDFSave exch store
  393.    (before exec) VMDEBUG
  394.      pdfshowpage_finish
  395.    (after exec) VMDEBUG
  396.    PDFSave restore
  397.  } bind def
  398.  
  399. /pdfpagecontents    % <pagedict> pdfpagecontents <contents>
  400.  { } bind def
  401.  
  402. /pdfshowpage_init   % <pagedict> pdfshowpage_init <pagedict>
  403.  { gsave
  404.    [ (%%Page: ) Page# ( ) 
  405.      DSCPageCount 1 add /DSCPageCount 1 index store #dsc
  406.    [ (GS_PDF_ProcSet begin) #dsc
  407.  } bind def
  408.  
  409. /pdfshowpage_setpage    % <pagedict> pdfshowpage_setpage <pagedict>
  410.  { 
  411.    3 dict   % for setpagedevice
  412.     % Stack: pagedict setpagedict
  413.     % We want to look at Rotate for displays, but not for printers.
  414.     % The following is a hack, but we don't know a better way to do this.
  415.    currentpagedevice /OutputFile known not
  416.     { dup /Orientation 3 index /Rotate pget not { 0 } if 90 idiv
  417.     % Rotate specifies *clockwise* rotation!
  418.       neg 3 and put
  419.     }
  420.    if
  421.     % Stack: pagedict setpagedict
  422.    1 index /MediaBox pget
  423.     {           % Set the page size.
  424.       boxrect [ 2 index 5 index sub 2 index 5 index sub ]
  425.     % Stack: pagedict setpagedict llx lly urx ury pagesize
  426.       5 index exch /PageSize exch put
  427.     % Stack: pagedict contents setpagedict llx lly urx ury
  428.       pop pop
  429.       neg exch neg exch
  430.       [ 3 1 roll ]
  431.     % Stack: pagedict setpagedict pageoffset
  432.       1 index exch /PageOffset exch put
  433.     }
  434.    if
  435.     % Stack: pagedict setpagedict
  436.    setpagedevice
  437.  } bind def
  438.  
  439. /pdfshowpage_finish % <pagedict> pdfshowpage_finish -
  440.  {
  441.     % Copy crop box.
  442.    dup /CropBox pget
  443.     { boxrect rectclip
  444.       dup /CropBox knownoget { mark /CropBox 3 -1 roll /PAGE pdfmark } if
  445.     }
  446.    if
  447.  
  448.     % Copy annotations and links.
  449.    dup /Annots knownoget
  450.     { 0 1 2 index length 1 sub
  451.        { 1 index exch oget
  452.          dup /Subtype oget annottypes exch .knownget { exec } { pop } ifelse
  453.        }
  454.       for pop
  455.     }
  456.    if
  457.  
  458.     % Display the actual page contents.
  459.    matrix currentmatrix /beginpage 0 # setmatrix
  460.    /Contents knownoget not { 0 array } if
  461.    dup type /arraytype ne { 1 array astore } if
  462.     { oforce false resolvestream pdfopdict .pdfrun } forall
  463.    /endpage 0 #
  464.    grestore
  465.    [ (end) #dsc
  466.  } bind def
  467.  
  468. end         % pdfdict
  469. .setglobal
  470.