henesyinit from p9fd787fda5 years agoHistory
1054 lines · 29.4 KB · Text
RawDownload
%    Copyright (C) 2000 Aladdin Enterprises.  All rights reserved.% % This file is part of AFPL Ghostscript.% % AFPL 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 Free Public License (the% "License") for full details.% % Every copy of AFPL 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 AFPL 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: pdfopt.ps,v 1.4 2000/12/01 04:15:52 lpd Exp $% PDF linearizer ("optimizer"). .currentglobal true .setglobal/pdfoptdict 200 dict defpdfoptdict begin % This linearizer is designed for simplicity, not for performance.% See the main program (the last procedure in the file) for comments% describing the main processing sequence. % ---------------- Utilities ---------------- % % ------ Data structures ------ % % Distinguish dictionaries, arrays, and everything else./ifdaelse {		% <obj> <dictproc> <arrayproc> <otherproc> ifdaelse -  3 index type dup /dicttype eq {    pop pop pop  } {    dup /arraytype ne exch /packedarraytype ne and {      exch    } if pop exch pop  } ifelse exec} bind def % Implement dynamically growable arrays using a dictionary./darray {		% <size> darray <darray>  dict} bind def/dadd {			% <darray> <value> dadd -  1 index length exch put} bind def/daforall {		% <darray> <proc> daforall -  /exch cvx /get cvx 3 -1 roll /exec cvx 5 packedarray cvx  0 1 2 index 0 get length 1 sub 4 -1 roll for} bind def/dacontents {		% <darray> dacontents <array>  [ exch { } daforall ]} bind def/dacontstring {		% <darray> dacontstring <string>  0 1 index { exch pop length add } forall string  dup /NullEncode filter			% Stack: darray str filter  3 -1 roll { 1 index exch writestring } daforall  closefile} bind def % Force an object, mapping it if it is a reference./omforcenew {		% <obj> omforce <obj'> <notseen>  dup oforce 2 copy eq { pop true } { exch 0 get omapnew exch pop } ifelse} bind def/omforce {		% <obj> omforce <obj'>  omforcenew pop} bind def/omget {		% <dict|array> <key> omget <obj>  get omforce} bind def% Visit an entire tree./omvisit {		% <obj> omvisit -  omforcenew {    { { omvisit omvisit } forall }    { { omvisit } forall }    { pop }    ifdaelse  } {    pop  } ifelse} bind def % Collect the list of currently mapped object numbers, in order./omapped {		% - omapped <obj#s>  RMap length array RMap {    2 index 3 1 roll 1 sub exch put  } forall} bind def % Collect the list of object numbers passed to omap by a procedure./visited {		% <proc> visited <obj#s>  false currentomap 2 .execn  omapped exch setomap} bind def % ------ Output ------ % % Provide a framework for closure-based streams..currentglobal false .setglobaluserdict /clostreams 20 dict put	% stream -> [data endproc].setglobal% Create a closure-based stream./clostream {		% <data> <proc> <endproc> clostream <stream>  2 index 3 -1 roll /exec load 3 packedarray cvx  /NullEncode filter		% Stack: data endproc stream  clostreams 1 index 5 -2 roll 2 array astore put} bind def% Close a closure-based stream./closend {		% <stream> closend <result>  dup closefile clostreams exch  2 copy get 3 1 roll undef aload pop exec} bind def % Implement in-memory output streams./msproc {		% <data> <more> <accum> msproc <scratch>  3 -1 roll dadd { 100 string } { () } ifelse} bind def/mstream {		% - mstream <mstream>  10 darray {msproc} {dacontstring} clostream} bind def/mcontents {		% <mstream> mcontents <string>  closend} bind def % Implement a stream that only keeps track of its position.% (All streams should do this, but the PLRM doesn't require it.)/posbuf 100 string def/posproc {		% <data> <more> <accum> posproc <scratch>  0 2 copy get 5 -1 roll length add put  pop //posbuf} bind def/postream {		% - postream <postream>  [0] {posproc} {0 get} clostream} bind def/poslength {		% <postream> poslength <pos>  closend} bind def % Implement streams with variable-bit-width data.% Note that these are dictionary objects, not stream objects./bitstream {		% <stream> bitstream <bstream>  4 dict begin /S exch def /N 8 def /B 0 def  currentdict end} bind def/bitwrite {		% <bstream> <value> <width> bitwrite -  PDEBUG { ( ) print 1 index =only (:) print dup = } if  3 -1 roll begin  N exch sub dup 0 ge {    /N exch def N bitshift B add  } {    2 copy bitshift B add S exch write			% Stack: value -left    { 8 add dup 0 ge { exit } if      2 copy bitshift 255 and S exch write    } loop    /N 1 index def bitshift 255 and  } ifelse /B exch def  end} bind def/bitflush {		% <bstream> bitflush -  begin N 8 ne { S B write /B 0 def /N 8 def } if end} bind def % Capture OFile output on the temporary file, in memory, or just as a length./totemp {		% <proc> totemp <start> <end>  TFile fileposition OFile  /OFile TFile def 3 .execn  /OFile exch def  TFile fileposition} bind def/tomemory {		% <proc> tomemory <string>  OFile /OFile mstream def 2 .execn  OFile mcontents exch /OFile exch def} bind def/tolength {		% <proc> tolength <string>  OFile /OFile postream def 2 .execn  OFile poslength exch /OFile exch def} bind def % Copy a range of bytes from TFile to OFile./copyrange {		% <start> <end> copybytes -  TFile 2 index setfileposition  exch sub 1024 string exch {		% Stack: buf left    2 copy 1 index length .min 0 exch getinterval    TFile exch readstring pop OFile exch writestring    1 index length sub dup 0 le { exit } if  } loop pop pop} bind def % Pad with blanks to a specified position./padto {		% <pos> padto -  OFile fileposition sub  dup 0 lt {    (ERROR: file position incorrect by ) print =    /padto cvx /rangecheck signalerror  } {    { ( ) ows } repeat  } ifelse} bind def % ---------------- Read objects into memory ---------------- % /touch {		% <object> touch -  {    { touch touch } forall  } {    dup xcheck {		% Executable array, must be an indirect object.      dup 0 get resolved? { pop pop } { oforce touch } ifelse    } {      { touch } forall    } ifelse  } {    pop  } ifdaelse} bind def % ---------------- Replace references with referents ---------------- % /replaceable? {		% <value> replaceable? <bool>  dup type /integertype eq exch xcheck not and} bind def/replacement {		% <obj|ref> replacement <obj'>  dup oforce dup replaceable? { exch } if pop} bind def /replacerefs {		% <object> replacerefs <object>  {    dup {      2 index 2 index undef      exch replacement exch replacement      2 index 3 1 roll put    } forall  } {    0 1 2 index length 1 sub {      1 index exch 2 copy get replacement put    } for  } {  } ifdaelse} bind def /replaceReferences {	% - replaceReferences -  Objects { replacerefs pop } lforall		% Delete replaced objects.  0 1 Objects llength 1 sub {    Objects 1 index lget replaceable? {      PDEBUG { (Deleting ) print dup = } if      Generations 1 index 0 lput    } if pop  } for} bind def % ---------------- Create new objects ---------------- % /createObjects {	% [<obj>...] createObjects <firstobj#>  Objects llength dup  dup 3 index length add growPDFobjects		% Stack: objects objn objn  3 1 roll exch {    Objects 2 index 3 -1 roll lput    Generations 1 index 1 lput    1 add  } forall pop} bind def % ---------------- Propagate attributes ---------------- % /nopropattrs <<	% Never propagate these.  /Type dup /Kids dup /Count dup /Parent dup	% Handle Resources specially.  /Resources dup>> def % Merge Resources./mergeres {		% <fromdict> <todict> mergeres -		% Values in todict take priority over fromdict.  1 index /Resources .knownget {    1 index /Resources .knownget {		% Stack: fromdict todict fromres tores      exch oforce exch oforce		% todict's Resources may be shared, so make a copy.      dup length dict .copydict      exch {		% Stack: fromdict todict tores' fromkey fromvalue	2 index 2 index knownoget {		% Stack: fromdict todict tores' fromkey fromvalue tovalue	  exch oforce exch		% ProcSet is an array, other types are dictionaries.	  dup type /dicttype eq {		% Dictionary, not ProcSet.	    exch dup length 2 index length add dict .copydict .copydict	  } {		% Array or packed array, ProcSet.		% Use dictionaries to do the merge.	    dup length 2 index length add dict begin	    exch { dup def } forall { dup def } forall	    mark currentdict end { pop } forall .packtomark	  } ifelse	} if	2 index 3 1 roll put      } forall    } if /Resources exch put pop  } {    pop pop  } ifelse} bind def % Merge attributes other than Resources./mergeattrs {		% <fromdict> <todict> mergeattrs <fromdict> <todict>		% Values in todict take priority over fromdict.  1 index {		% Stack: fromdict todict fromkey fromvalue    //nopropattrs 2 index known {      pop pop    } {      2 index 2 index known { pop pop } { 2 index 3 1 roll put } ifelse    } ifelse  } forall} bind def % Propagate attributes to a subtree./proppage {		% <attrs> <subtree> proppage -		% 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 {		% Accumulate inherited values.    3 1 roll		% Stack: kids attrs pagesnode    dup length dict .copydict mergeattrs    dup 3 1 roll mergeres    exch { oforce 1 index exch proppage } forall pop  } {		% Merge inherited values into the leaf.    mergeattrs mergeres  } ifelse} bind def % Propagate attributes to all pages./propagateAttributes {	% - propagateAttributes -  0 dict Trailer /Root oget /Pages oget proppage} bind def % ---------------- Identify document-level objects ---------------- % /identifyDocumentObjects {	% - identifyDocumentObjects <obj#s>  {    Trailer /Root omget    dup /PageMode .knownget { omvisit } if    dup /OpenAction .knownget { omvisit } if    Trailer /Encrypt .knownget { omvisit } if    dup /Threads .knownget {      omforce { omforce } forall    } if    dup /AcroForm .knownget { omvisit } if    pop  } visited} bind def % ---------------- Identify the objects of each page ---------------- % /identifyfont {		% <fontref> identifyfont -  omforce {    exch /FontDescriptor eq {      omforce dup /Flags .knownget { 32 and 0 ne } { false } ifelse      exch {	exch dup dup /FontFile eq exch /FontFile2 eq or	exch /FontFile3 eq or 2 index and {	  fontfiles exch dadd	} {	  omvisit	} ifelse      } forall pop    } {      omvisit    } ifelse  } forall} bind def /identifyPageObjects {	% <extra> <page#> identifyPageObjects <obj#s>  pdffindpageref  4 dict begin  /images 10 darray def  /fontfiles 10 darray def  {    omforce		% Stack: extra page		% Visit any extra objects if applicable.    exch omvisit		% Visit Annots, if any.		% We don't try to defer the drawing information.    dup /Annots .knownget { omvisit } if		% Visit beads.    dup /B .knownget { omvisit } if		% Visit resources dictionaries.    dup /Resources .knownget {      omforce dup {		% Visit the first-level Resource dictionaries.	omforce pop pop      } forall {		% Visit the resources themselves.		% Skip Image XObjects, and FontFile streams if the		% FontDescriptor Flags have bit 6 set.		% We don't try to visit the resources in the order in which		% the Contents stream(s) reference(s) them.	exch dup /XObject eq {	  pop oforce {	    dup oforce /Subtype get /Image eq {	      images exch dadd	    } {	      omvisit	    } ifelse pop	  } forall	} {	  /Font eq {	    oforce { identifyfont pop } forall	  } {	    oforce omvisit	  } ifelse	} ifelse      } forall    } if		% Visit the Contents stream(s).    dup /Contents .knownget { omvisit } if		% Visit Image XObjects.  We don't try to visit them in		% reference order.    images { omvisit } daforall		% Visit FontFile streams.  We don't try to visit them in		% reference order.    fontfiles { omvisit } daforall    pop  } visited end} bind def % Identify the objects of the first page./identifyFirstPageObjects {	% -identifyFirstPageObjects <obj#s>  Trailer /Root oget null  1 index /PageMode knownoget {    /UseOutlines eq {      pop dup /Outlines get    } if  } if exch pop  1 identifyPageObjects} bind def % Identify the non-shared objects of the other pages, and the shared objects./identifyOtherPageObjects {	% - identifyOtherPageObjects [<pageobj#s> ...]				%   <sharedobj#s>  4 dict begin  /marks lstring Objects llength lgrowto def		% Mark document-level and first page objectsw.  [CatalogNs FirstPageNs] {    { marks exch 255 lput } forall  } forall		% Collect objects of other pages and identify sharing.  [ 2 1 pdfpagecount { null exch identifyPageObjects } for ]  dup {    { marks exch 2 copy lget 1 add 254 min lput } forall  } forall  [ exch {    [ exch {      marks 1 index lget 1 ne { pop } if    } forall ]  } forall ]  [ 1 1 marks llength 1 sub {    marks 1 index lget dup 1 le exch 255 eq or { pop } if  } for ]  end} bind def % Identify objects not associated with any page./identifyNonPageObjects {	% - identifyNonPageObjects <obj#s>  4 dict begin  /marks lstring Objects llength lgrowto def  [[[LPDictN PHSN] CatalogNs FirstPageNs SharedNs] OtherPageNs] {    { { marks exch 1 lput } forall } forall  } forall	%****** PUT THESE IN A REASONABLE ORDER ******  [ 1 1 Objects llength 1 sub {    marks 1 index lget 0 eq {      Generations 1 index lget 0 eq { pop } if    } {      pop    } ifelse  } for ]} bind def % ---------------- Assign object numbers ---------------- % % Assign object numbers to all objects that will be copied.% Return the first (translated) object number in the First Page xref table.

Lines 1–500 of 1054.