Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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