home *** CD-ROM | disk | FTP | other *** search
/ Freelog Special Freeware 31 / FreelogHS31.iso / PDF / Ghostscript / gs860w32.exe / gs8.60 / lib / pdfwrite.ps < prev    next >
Text File  |  2007-07-13  |  11KB  |  385 lines

  1. %    Copyright (C) 1999, 2000, 2001 Aladdin Enterprises.  All rights reserved.
  2. % This software is provided AS-IS with no warranty, either express or
  3. % implied.
  4. % This software is distributed under license and may not be copied,
  5. % modified or distributed except as expressly authorized under the terms
  6. % of the license contained in the file LICENSE in this distribution.
  7. % For more information about licensing, please refer to
  8. % http://www.ghostscript.com/licensing/. For information on
  9. % commercial licensing, go to http://www.artifex.com/licensing/ or
  10. % contact Artifex Software, Inc., 101 Lucas Valley Road #110,
  11. % San Rafael, CA  94903, U.S.A., +1(415)492-9861.
  12.  
  13. % $Id: pdfwrite.ps 8120 2007-07-13 01:10:56Z alexcher $
  14. % Writer for transmuting PDF files.
  15.  
  16. % NOTES:
  17. % We do editing by replacing objects (in the cache) and then doing a
  18. %   simple recursive walk with object renumbering.
  19. % Free variables:
  20. %   RMap [per input file] (dict): input_obj# => output_obj#
  21. %   PDFfile (file): current input file
  22. %   OFile (file): current output file
  23. %   XRef (dict): output_obj# => output_file_pos
  24. %   ToWrite: 0..N-1 => [obj# gen#]
  25.  
  26. /.setlanguagelevel where { pop 2 .setlanguagelevel } if
  27. .currentglobal true .setglobal
  28.  
  29. /PDFWRDEBUG where { pop } { /PDFWRDEBUG false def } ifelse
  30.  
  31. % ======== Long dictionary support =============== %
  32.  
  33. % The key must be a non-negative iteger.
  34.  
  35. /ld_dict {          % <len> ld_dict <ldict>
  36.   pop << 0 <<>> >>
  37. } bind def
  38.  
  39. /ld_length {        % <ldict> ld_length <length>
  40.   0 exch { exch pop length add } forall
  41. } bind def
  42.  
  43. /ld_get {           % <ldict> <key> ld_get <any>
  44.   dup 3 1 roll -15 bitshift get exch get
  45. } bind def
  46.  
  47. /ld_put {           % <ldict> <key> <any> ld_put -
  48.   3 1 roll dup               % any ldict key key
  49.   4 1 roll -15 bitshift      % key any ldict key>>15
  50.   2 copy known {
  51.     get                      % key any subdict
  52.     3 1 roll put             % -
  53.   } {
  54.     64 dict dup 6 1 roll     % <<>> key any ldict key>>15 <<>>
  55.     put put
  56.   } ifelse                   % -
  57. } bind def
  58.                     
  59. /ld_known {         % <ldict> <key> ld_known <bool>
  60.   dup 3 1 roll -15 bitshift  % key <<>> key<<15
  61.   2 copy known {
  62.     get exch known
  63.   } {
  64.     pop pop pop //false
  65.   } ifelse
  66. } bind def
  67.                              
  68. /ld_knownget {      % <ldict> <key> ld_known false | <any> true
  69.   dup 3 1 roll -15 bitshift  % key <<>> key<<15
  70.   2 copy known {
  71.     get exch .knownget
  72.   } {
  73.     pop pop pop //false
  74.   } ifelse
  75. } bind def
  76.  
  77. /ld_def {           % <key> <any> ld_def -
  78.   currentdict 3 1 roll ld_put
  79. } bind def
  80.  
  81. /ld_forall {        % <ldict> <proc} ld_forall -
  82.   { forall exch pop } aload pop
  83.   4 2 roll 4 packedarray cvx forall
  84. } bind def
  85.  
  86. /ld_clone {         % <ldict> ld_clone <ldict copy>
  87.   << exch { dup length dict copy } forall >>
  88. } bind def
  89.  
  90. % ================ Object mapping ================ %
  91.  
  92. % Initialize the object number and location map.
  93. /omapinit {        % - omapinit -
  94.   /RMap 100 ld_dict def
  95.   /XRef 100 ld_dict def
  96.   PDFWRDEBUG { (omapinit) = } if
  97. } bind def
  98.  
  99. % Map an object number.
  100. /omapnew {        % <oldobj#> omap <newobj#> <isnew>
  101.   RMap 1 index ld_knownget {
  102.     exch pop //false
  103.   } {
  104.     PDFWRDEBUG { (omap\() print dup =only } if
  105.     RMap dup ld_length 1 add   % old# <<>> len+1
  106.     2 index exch dup           % old# <<>> old# len+1 len+1
  107.     5 1 roll                   % len+1 old# <<>> old# len+1
  108.     ld_put pop //true          % len+1 true
  109.     PDFWRDEBUG { (\) = ) print 1 index = } if
  110.   } ifelse
  111. } bind def
  112. /omap {            % <oldobj#> omap <newobj#>
  113.   omapnew pop
  114. } bind def
  115.  
  116. % Save and restore the object map.
  117. % Note that currentomap either returns a copy or calls omapinit.
  118. /currentomap {        % <copy> currentomap <omap>
  119.   {
  120.     [RMap ld_clone XRef ld_clone]
  121.   } {
  122.     [RMap XRef] omapinit
  123.   } ifelse
  124. } bind def
  125. /setomap {        % <omap> setomap -
  126.   aload pop /XRef exch def /RMap exch def
  127.   PDFWRDEBUG {
  128.     (setomap: #Xref = ) print XRef ld_length =only
  129.     (, #RMap = ) print RMap ld_length =
  130.   } if
  131. } bind def
  132.  
  133. % ================ Writing ================ %
  134.  
  135. % ---------------- Low-level output ---------------- %
  136.  
  137. % Write a string on the output file.
  138. /ows {            % <string> ows -
  139.   OFile exch writestring
  140. } bind def
  141.  
  142. % ---------------- Scalars ---------------- %
  143.  
  144. % Note that the '#' character isn't legal in a name unless it is a prefix
  145. % for a hex encoded character (for PDF 1.2 and later). The following assumes
  146. % that the names are already valid PDF 1.2+ names so that  we can treat the
  147. % '#' as a legal character. The next two hex characters are already in the
  148. % set of valid name characters. PDF 1.1 and earlier allowed spaces in names
  149. % which probably wouldn't make it past the tokenizer anyway.
  150. /pdfnamechars
  151.   (!"#$&'*+,-.0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ\\^_`abcdefghijklmnopqrstuvwxyz|~)
  152. readonly def
  153. /pdfwritename {        % <name> pdfwritename -
  154.   (/) ows .namestring {
  155.     ( ) dup 0 4 -1 roll put
  156.     //pdfnamechars 1 index search {
  157.       pop pop pop
  158.     } {
  159.       pop 0 get 256 add 16 =string cvrs
  160.       dup 0 (#) 0 get put
  161.     } ifelse ows
  162.   } forall
  163. } bind def
  164.  
  165. % ---------------- Composite objects ---------------- %
  166.  
  167. /pdfwriteprocs mark
  168.   /resolveR { pdfwriteref }
  169.   /O { pdfwritenewref }
  170. .dicttomark readonly def
  171. /pdfwritearray {    % <array> pdfwritearray -
  172.   dup xcheck {
  173.     aload pop //pdfwriteprocs exch get exec
  174.   } {
  175.     % Because of a bug in Acrobat's parser for linearization parameters,
  176.     % we have to include some whitespace after the opening [ (!).
  177.     ([ ) ows { pdfwritevalue (\n) ows } forall (]) ows
  178.   } ifelse
  179. } bind def
  180.  
  181. /pdfwritedict {        % <dict> pdfwritedict -
  182.   dup xcheck {
  183.     pdfwritestream
  184.   } {
  185.     (<<) ows {
  186.       exch pdfwritevalue ( ) ows pdfwritevalue (\n) ows
  187.     } forall (>>) ows
  188.   } ifelse
  189. } bind def
  190.  
  191. % ---------------- References ---------------- %
  192.  
  193. /pdfwritenewref {    % <newobj#> pdfwritenewref -
  194.   OFile exch write=only ( 0 R) ows
  195. } bind def
  196.  
  197. /pdfwriteref {        % <obj#> <gen#> pdfwriteref -
  198.   1 index omapnew {
  199.     ToWrite dup length 5 -2 roll 2 packedarray put
  200.   } {
  201.     exch pop exch pop
  202.   } ifelse
  203.   pdfwritenewref
  204. } bind def
  205.  
  206. /pdfcopystring 200 string def
  207. /pdfwritestream {    % <streamdict> pdfwritestream -
  208.     % Remove File, FilePosition, and StreamKey;
  209.     % optimize by replacing an indirect Length.
  210.   dup dup length dict copy
  211.     % Stack: origdict dict
  212.   dup /File undef dup /FilePosition undef dup /StreamKey undef
  213.   dup /Length known {
  214.     dup /Length get dup oforce ne {
  215.       dup /Length 2 copy oget put
  216.     } if
  217.   } {
  218.     1 index /File get dup
  219.     3 index /FilePosition get setfileposition
  220.     dup 0 (endstream) /SubFileDecode filter flushfile
  221.     .fileposition 9 sub
  222.     2 index /FilePosition get sub
  223.     1 index exch /Length exch put
  224.   } ifelse
  225.   exch dup /File get dup 3 -1 roll /FilePosition get setfileposition
  226.   pdfcopystream
  227. } bind def
  228.  
  229. % We put copying the stream contents in separate procedures so that we
  230. % can replace this function if desired.
  231. /pdfcopybytes {        % <fromfile> <tofile> <length> pdfcopybytes -
  232.   {
  233.     dup 0 eq { exit } if
  234.     //pdfcopystring 0 2 index 2 index length .min getinterval
  235.     3 index exch readstring 3 1 roll
  236.     3 index 1 index writestring length sub exch not { exit } if
  237.   } loop pop pop pop
  238. } bind def
  239. /pdfcopystream {    % <newstreamdict> <file> pdfcopystream -
  240.             %   (file has been positioned)
  241.   1 index pdfwritevalue (stream\n) ows
  242.   exch /Length get OFile exch pdfcopybytes
  243.   (endstream) ows
  244. } bind def
  245.  
  246. % ---------------- General values/objects ---------------- %
  247.  
  248. /pdfwritetypes mark
  249.     % Scalars
  250.   /nulltype { pop (null) ows } bind
  251.   /integertype { =string cvs ows } bind
  252.   /booleantype 1 index
  253.   /realtype {
  254.     =string cvs
  255.     (e) search {  % PDF has no exponential format
  256.       exch pop % exp pre
  257.       exch cvi exch
  258.       (-) anchorsearch { ows } if
  259.       (.) search {
  260.         exch pop            % exp (frac) (int)
  261.         1 index length      % exp (frac) (int) len
  262.         3 1 roll            % exp len (frac) (int)
  263.         exch concatstrings  % exp len (int_frac)
  264.         3 1 roll sub        % (int_frac) exp-len
  265.         exch                % exp-len (int_frac)
  266.       } if                  % exp (mant)
  267.       1 index 0 ge {
  268.         ows { (0) ows } repeat (.) ows
  269.       } {
  270.         dup length          % exp (mant) len
  271.         3 -1 roll add       % (mant) exp+len
  272.         dup 0 le {
  273.           (0.) ows neg { (0) ows } repeat ows
  274.         } {
  275.           2 copy 0 exch getinterval ows
  276.           (.) ows
  277.           1 index length 1 index sub getinterval ows
  278.         } ifelse
  279.       } ifelse
  280.     } {
  281.       ows
  282.     } ifelse
  283.   } bind
  284.   /stringtype { OFile exch write===only } bind
  285.   /nametype { pdfwritename } bind
  286.     % Composite/reference objects
  287.   /arraytype { pdfwritearray } bind
  288.   /packedarraytype 1 index
  289.   /dicttype { pdfwritedict } bind
  290. .dicttomark readonly def
  291.  
  292. /pdfwritevalue {    % <obj> pdfwritevalue -
  293.   PDFWRDEBUG { (****Writing: ) print dup === flush } if
  294.   //pdfwritetypes 1 index type get exec
  295. } bind def
  296.  
  297. % We make pdfwriteobjdef a separate procedure for external use.
  298. /pdfwriteobjheader {    % <newobj#> pdfwriteobjheader -
  299.   XRef 1 index OFile .fileposition ld_put
  300.   PDFWRDEBUG { (XRef\() print dup =only (\) = ) print XRef 1 index ld_get = } if
  301.   OFile exch write=only ( 0 obj\n) ows
  302. } bind def
  303. /pdfwriteobjdef {    % <newobj#> <value> pdfwriteobjdef -
  304.   exch pdfwriteobjheader
  305.   pdfwritevalue (\nendobj\n) ows
  306. } bind def
  307. /pdfwriteobj {        % <obj#> <gen#> pdfwriteobj -
  308.   1 index exch resolveR exch omap exch pdfwriteobjdef
  309. } bind def
  310.  
  311. % ---------------- File-level entities ---------------- %
  312.  
  313. % Write a PDF file header.
  314. % Free variables: OFile, PDFversion.
  315. /pdfwriteheader {    % - pdfwriteheader -
  316.   (%PDF-) ows OFile PDFversion write=
  317.   (%\347\363\317\323\n) ows
  318. } bind def
  319.  
  320. % Write a cross-reference table and trailer.
  321. /pdfwritexref {        % <firstobj#> <#objs> pdfwritexref -
  322.   (xref\n) ows
  323.   OFile 2 index write=only ( ) ows OFile 1 index write=
  324.   1 index add 1 sub 1 exch {
  325.     dup 0 eq {
  326.       pop (0000000000 65535 f \n) ows
  327.     } {
  328.       XRef exch ld_get 1000000000 add =string cvs
  329.       dup 0 (0) 0 get put
  330.       ows ( 00000 n \n) ows
  331.     } ifelse
  332.   } for
  333. } bind def
  334. /pdfwritetrailer {    % <trailer> pdfwritetrailer -
  335.   (trailer\n) ows pdfwritevalue (\n) ows
  336. } bind def
  337. /pdfwritestartxref {    % <startpos> pdfwritestartxref -
  338.   (startxref\n) ows OFile exch write=
  339.   (%%EOF\n) ows
  340. } bind def
  341.  
  342. % ================ Top-level control ================ %
  343.  
  344. /pdfwrite {        % <file> <trailer> pdfwrite -
  345.   10 dict begin
  346.   /trailer exch def
  347.   /OFile exch def
  348.   /ToWrite 100 dict def
  349.   omapinit
  350.  
  351.     % Write the PDF file header.
  352.  
  353.   pdfwriteheader
  354.  
  355.     % Write the objects.
  356.  
  357.   trailer {
  358.     exch pop dup xcheck {    % The only executable objects are references.
  359.       aload pop pop pdfwriteobj
  360.     } {
  361.       pop
  362.     } ifelse
  363.   } forall
  364.     % Walk the object graph.
  365.   {
  366.     ToWrite dup length dup 0 eq { pop pop exit } if
  367.     1 sub 2 copy get 3 1 roll undef aload pop pdfwriteobj
  368.   } loop
  369.  
  370.     % Write the xref table and trailer.
  371.  
  372.   /xref OFile fileposition def
  373.   0 XRef ld_length 1 add pdfwritexref
  374.   trailer dup length 1 add dict copy
  375.   dup /Size XRef ld_length 1 add put pdfwritetrailer
  376.   xref pdfwritestartxref
  377.  
  378.   end
  379. } bind def
  380.  
  381. .setglobal
  382.