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) 1994, 2000 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: pdf_main.ps,v 1.100 2005/09/23 18:21:23 ray Exp $
17
% pdf_main.ps
18
% PDF file- and page-level operations.
19
 
20
/.setlanguagelevel where { pop 2 .setlanguagelevel } if
21
.currentglobal true .setglobal
22
/pdfdict where { pop } { /pdfdict 100 dict def } ifelse
23
pdfdict begin
24
 
25
% Patch in an obsolete variable used by some third-party software.
26
/#? false def
27
 
28
% Test whether the current output device handles pdfmark.
29
/.writepdfmarkdict 1 dict dup /pdfmark null put readonly def
30
/.writepdfmarks {	% - .writepdfmarks <bool>
31
  currentdevice //.writepdfmarkdict .getdeviceparams
32
  mark eq { false } { pop pop true } ifelse
33
  systemdict /DOPDFMARKS known or 
34
} bind def
35
 
36
% For simplicity, we use a single interpretation dictionary for all
37
% PDF graphics execution, even though this is too liberal.
38
/pdfopdict mark
39
  objopdict { } forall
40
  drawopdict { } forall
41
  /endstream { exit } bind
42
  (%%EOF) cvn { exit } bind		% for filters
43
	% PDF 1.1 operators
44
  /BX { /BXlevel BXlevel 1 add store } bind
45
  /EX { /BXlevel BXlevel 1 sub store } bind
46
  /PS { cvx exec } bind
47
	% PDF 1.2 operators
48
  /BMC { pop } bind
49
  /BDC { pop pop } bind
50
  /EMC { }
51
  /MP { pop } bind
52
  /DP { pop pop } bind
53
.dicttomark readonly def
54
 
55
% ======================== Main program ======================== %
56
 
57
end			% pdfdict
58
userdict begin
59
 
60
/defaultfontname /Times-Roman def
61
 
62
% Make sure the registered encodings are loaded, so we don't run the risk
63
% that some of the indices for their names will overflow the packed
64
% representation.  (Yes, this is a hack.)
65
SymbolEncoding pop
66
DingbatsEncoding pop
67
 
68
% Redefine 'run' so it recognizes PDF files.
69
systemdict begin
70
/.runps /run load def
71
/run {
72
  dup type /filetype ne { (r) file } if
73
  % skip leading whitespace characters (actually anything less than or equal to <sp>)
74
  { dup ( ) .peekstring not { false exit } if
75
    dup 0 get 32 le { pop dup read pop pop } { true exit } ifelse
76
  } loop
77
  {
78
    (%) eq {
79
      dup (     ) .peekstring {
80
	(%PDF-) eq {
81
	    dup (%stdin) (r) file eq {
82
	      % Copy PDF from stdin to temporary file then run it.
83
	      null (w+) //systemdict /.tempfile get exec exch 3 1 roll
84
	      % stack: tempname stdin tempfile
85
	      64000 string
86
	      {
87
		% stack: tempname stdin tempfile string
88
		2 index 1 index readstring
89
		exch 3 index exch writestring
90
		not { exit } if
91
	      }
92
	      loop
93
	      pop exch closefile
94
	      % stack: tempname tempfile
95
	      dup 0 setfileposition
96
	      dup runpdf
97
	      closefile deletefile
98
	    } {
99
	      runpdf
100
	    } ifelse
101
	  } {
102
	    cvx .runps % doesn't start with %PDF-
103
	  } ifelse
104
	} {
105
	  pop cvx .runps % didn't read 5 characters
106
	} ifelse
107
    } {
108
      cvx .runps % didn't start with %
109
    } ifelse
110
  } {
111
    pop closefile % file was empty
112
  } ifelse
113
} bind odef
114
currentdict /runpdfstring .undef
115
 
116
 
117
/runpdfbegin {		% <file> runpdf -
118
   userdict begin
119
	% It turns out that the PDF interpreter uses memory more
120
	% effectively if it is run under at least one level of save.
121
	% This is counter-intuitive, and we don't understand why it happens,
122
	% but the improvement is significant.
123
   /PDFTopSave save def
124
 
125
   /Page# null def
126
   /Page null def
127
   /DSCPageCount 0 def
128
   /PDFSave null def
129
   GS_PDF_ProcSet begin
130
   pdfdict begin
131
   pdfopen begin
132
   Trailer /Root oget /Pages oget /CropBox knownoget
133
    { oforce_array normrect mark /CropBox 3 -1 roll /PAGES pdfmark
134
    }
135
   if
136
   /FirstPage where 
137
    { pop FirstPage dup pdfpagecount gt
138
      { (\nRequested FirstPage is greater than the number of pages in the file: ) print
139
        pdfpagecount = flush
140
      } if
141
    } {
142
      1
143
    } ifelse
144
   /LastPage where { pop LastPage pdfpagecount .min } { pdfpagecount } ifelse
145
   1 index 1 index gt
146
    { (   No pages will be processed \(FirstPage > LastPage\).) = flush }
147
    { QUIET not
148
      { (Processing pages ) print 1 index =only ( through ) print dup =only
149
        (.) = flush
150
      }
151
     if
152
    }
153
   ifelse
154
} bind def
155
 
156
/dopdfpages {   % firstpage# lastpage# dopdfpages -
157
  << /PDFScanRules true >> setuserparams	% set scanning rules for PDF vs. PS
158
  1 exch
159
    { dup /Page# exch store
160
      QUIET not { (Page ) print dup == flush } if
161
      pdfgetpage pdfshowpage
162
    } for
163
  << /PDFScanRules null >> setuserparams	% restore scanning rules for PS
164
} bind def
165
 
166
/runpdfend {
167
   Repaired { printrepaired } if
168
   currentdict pdfclose
169
   end			% temporary dict
170
   end			% pdfdict
171
   end			% GS_PDF_ProcSet
172
   PDFTopSave restore
173
   end			% userdict
174
} bind def
175
 
176
/runpdf {		% <file> runpdf -
177
  runpdfbegin
178
  dopdfpages
179
  runpdfend
180
} bind def
181
 
182
end			% systemdict
183
% Redefine the procedure that the C code uses for running piped input.
184
% It is OK to use { (%stdin) run } here, because a startjob cannot occur.
185
/.runstdin {
186
  { (%stdin) run } execute0
187
} bind def
188
 
189
end			% userdict
190
pdfdict begin
191
 
192
% ======================== File parsing ======================== %
193
 
194
% Read the cross-reference and trailer sections.
195
 
196
/traileropdict mark
197
  (<<) cvn { mark } bind
198
  (>>) cvn { { .dicttomark } stopped {
199
	      (   **** File has unbalanced >> in trailer.\n) pdfformaterror
200
             } if } bind
201
  ([) cvn { mark } bind		% ditto
202
  (]) cvn dup load
203
%  /true true		% see .pdfexectoken in pdf_base.ps
204
%  /false false		% ibid.
205
%  /null null		% ibid.
206
  /R { /resolveR cvx 3 packedarray cvx } bind	% see Objects below
207
  /startxref /exit load
208
.dicttomark readonly def
209
 
210
% Because of EOL conversion, lines with fixed contents might be followed
211
% by one or more blanks.
212
/lineeq			% <filestr> <conststr> lineeq <bool>
213
 { anchorsearch
214
    { pop { ( ) anchorsearch not { () eq exit } if pop } loop }
215
    { pop false }
216
   ifelse
217
 } bind def
218
/linene { lineeq not } bind def
219
 
220
 %  Read original version (pre PDF 1.5) of the xref table.
221
 %  Note:  The position is the location of 'xref'.  The current PDFfile
222
 %  position is just after the 'XREF'.
223
/readorigxref		% <pos> readorigxref <trailerdict>
224
 {
225
   pop				% We do not need the position.
226
 
227
   { PDFfile token pop		% first object # or trailer
228
     dup /trailer eq { pop exit } if
229
     PDFfile pdfstring readline pop
230
     token pop			% entry count
231
     % remaining must be whitespace only (otherwise this xref Size was invalid.
232
     exch dup length 0 ne {
233
       false 1 index { 32 gt { pop true exit } if } forall {
234
         (   **** Warning: xref subsection header has extra characters.\n)
235
         pdfformaterror
236
         /setxrefentry cvx /syntaxerror signalerror
237
       } if
238
     } if
239
     pop			% remove last
240
		% This section might be adding new objects:
241
		% ensure that Objects and Generations are big enough.
242
		% stack: <err count> <first obj> <entry count>
243
     2 copy add growPDFobjects
244
     {				% stack: <err count> <obj num>
245
		% Read xref line
246
       PDFfile 20 string readstring pop  % always read 20 chars.
247
       token pop		% object position
248
       exch token pop		% generation #
249
       exch token pop		% n or f
250
       exch			% stack: <err count> <obj#> <loc> <gen#> <tag> <remainder of line>
251
       dup length 0 ne {
252
         % check to make sure trailing garbage is just white space
253
	 dup { 32 gt { 5 -1 roll 1 add 5 1 roll } if } forall   % bump error count on garbage
254
       } if
255
       pop			% Stack: <err count> <obj#> <loc> <gen#> <tag>
256
       dup /n eq {		% xref line tag is /n
257
	 pop			% pop dup of line tag
258
         Objects 3 index lget null eq {	% later update might have set it
259
 
260
	   setxrefentry		% Save xref entry
261
	   3 -1 roll pop	% Remove ObjectStream object onumber
262
         } if
263
       }
264
       {			% xref line tag was not /n
265
	 /f ne			% verify that the tag was /f
266
         { /setxrefentry cvx /syntaxerror signalerror
267
	 } if
268
       } ifelse
269
       pop pop			% pop <obj location> and <gen num>
270
       % stack: <err count> <obj num>
271
       1 add			% increment object number
272
     } repeat
273
     pop			% pop <obj #>
274
   } loop
275
 
276
     (   **** Warning:  length of some xref entries is not equal to 20 bytes.\n)
277
     pdfformaterror
278
   } if
279
   PDFfile traileropdict .pdfrun
280
 } bind def
281
 
282
 % This dicitonary is used to read the xref dictionary.  It should work for
283
 % reading any dictionary.  dictlevelcount must contain 0.
284
/xrefopdict mark
285
  (<<) cvn { /dictlevelcount dictlevelcount 1 add def mark } bind
286
  (>>) cvn { .dicttomark /dictlevelcount dictlevelcount 1 sub def
287
  	     dictlevelcount 0 eq { exit} if } bind
288
  ([) cvn { mark } bind		% ditto
289
  (]) cvn dup load
290
%  /true true		% see .pdfexectoken in pdf_base.ps
291
%  /false false		% ibid.
292
%  /null null		% ibid.
293
  /R { /resolveR cvx 3 packedarray cvx } bind	% see Objects below
294
.dicttomark readonly def
295
 
296
% Get a variable length positive integer value from a stream.  A value
297
% of zero is returned if the count is zero.
298
/getintn {	% <stream> <count> getintn int
299
 
300
  exch pop			% Discard stream
301
} bind def
302
 
303
% This array contains handlers for processing the different types of
304
% entries in the XRef stream.
305
% Stack: <Xrefdict> <xref stream> <Index array> <pair loc> <obj num>
306
% 	 <field 2> <field 3>
307
% The handlers leave the stack unchanged.
308
/xref15entryhandlers [
309
  {	% XRef entry type 0 - free or f type xref entry
310
%    (free ) print
311
%    (obj num: ) print 2 index pdfstring cvs print ( ) print
312
%    (loc: ) print 1 index pdfstring cvs print ( ) print
313
%    (gen: ) print dup === flush
314
  } bind		% Do nothing for free xref entries
315
	% XRef entry type 1 - normal or n type xref entry
316
  {	% field 2 = obj loc, field 3 = gen num
317
%    (normal ) print
318
%    (obj num: ) print 2 index pdfstring cvs print ( ) print
319
%    (loc: ) print 1 index pdfstring cvs print ( ) print
320
%    (gen: ) print dup === flush
321
 
322
    setxrefentry
323
    3 -1 roll pop		% remove stream number
324
  } bind
325
	% XRef entry type 2 - compressed object type xref entry
326
  {	% field 2 = object stream num, field 3 = index into object stream
327
%    (Compressed objects: ) print
328
%    (obj num: ) print 2 index pdfstring cvs print ( ) print
329
%    (field 2: ) print 1 index pdfstring cvs print ( ) print
330
%    (field 3: ) print dup === flush
331
 
332
  } bind
333
] def
334
 
335
 %  Read the PDF 1.5 version of the xref table.
336
 %  Note:  The position is the location of the start of the dictionary object
337
 %  In PDF 1.5, the XRef dictionary also serves as the trailer dictionary
338
/readpdf15xref		% <pos> readpdf15xref <trailerdict>
339
 {
340
   PDFfile exch setfileposition		% move to start of object
341
   	% Get object number, revision, and 'obj' and discard
342
   PDFfile token pop pop
343
   PDFfile token pop pop
344
   PDFfile token pop pop
345
	% Get the XRef dicitionary
346
   /dictlevelcount 0 def PDFfile xrefopdict .pdfrun
347
	% Verify that we have an XRef dictionary
348
   dup /Type get /XRef ne {
349
     /readpdf15xref cvx /syntaxerror signalerror
350
   } if
351
   	% Ensure that we we have room in the objects array, etc.
352
   dup /Size get growPDFobjects
353
	% Create a stream for the XRef data
354
   PDFfile token pop pop		% Skip over 'stream'
355
   dup stream false resolvestream
356
   	% Stack: <XRefdict> <xref stream>
357
	% The Index array defines the ranges of object numbers in the
358
	% XRef stream.  Each value pair is consists of starting object
359
	% number and the count of consecutive objects.
360
	% Get the Index array, if present
361
   1 index /Index .knownget not {	% If no Index array ...
362
     [ 0 3 index /Size get ]		% Default = [ 0 Size ]
363
   } if
364
	% Loop through the Index array
365
 
366
	% Get start and end of object range
367
     2 copy get				% Start of the range
368
     dup 3 index 3 index 1 add get 	% Number of entries in range
369
     	% Loop through the range of object numbers
370
     add 1 sub 1 exch {			% Form end of range, set increment = 1
371
	% Stack: <Xrefdict> <xref stream> <Index array> <pair loc> <obj num>
372
	% Get xref parameters.  Note:  The number of bytes for each parameter
373
	% is defined by the entries in the W array.
374
       4 index /W get aload pop		% Get W array values
375
       	% The first field indicates type of entry.  Get first field value.
376
	% If the num. of bytes for field 1 is 0 then default field value is 1
377
       3 -1 roll dup 0 eq { pop 1 } { 6 index exch getintn } ifelse
378
	% Get the handler for the xref entry type.  We will execute the
379
	% handler after we get the other two field values.
380
       xref15entryhandlers exch get
381
       3 -1 roll 6 index exch getintn	% Get second field
382
       3 -1 roll 6 index exch getintn	% Get third field
383
       3 -1 roll exec			% Execute Xref entry handler
384
       pop pop pop			% Remove field values and obj num
385
     } for				% Loop through Xref entries
386
     pop				% Remove Index array pair loc
387
   } for				% Loop through Index array entries
388
   pop pop				% Remove Index array and xref stream
389
 } bind def
390
 
391
% Read the cross-reference table.
392
% <pos> is the position either from the startxref statement or the /Prev
393
% entry in the prior trailer dictionary.
394
/readxref		% <pos> readxref <trailerdict>
395
 {
396
   PDFoffset add PDFfile exch setfileposition
397
		% In some PDF files, this position actually points to
398
		% white space before the xref line.  Skip over this here.
399
   {
400
     PDFfile fileposition PDFfile read pop 32 gt { exit } if pop
401
   } loop
402
   dup		% Make copy of the file position (before last char was read).
403
   PDFfile exch setfileposition
404
		% The PDF specification says that the 'xref' must be on a line
405
		% by itself. The code here formerly used readline and linene to
406
		% check this. However, Acrobat Reader only requires the line to
407
		% begin with 'xref', and there are enough applications producing
408
		% non-compliant PDF files that we have to do this too.
409
   PDFfile pdfstring 0 4 getinterval readstring pop
410
   (xref) eq
411
   { readorigxref } 	% 'xref' -> original xref table
412
   { readpdf15xref }	% otherwise assume PDF 1.5 xref stream
413
   ifelse
414
 } bind def
415
 
416
% Open a PDF file and read the header, trailer, and cross-reference.
417
/pdfopen {		% <file> pdfopen <dict>
418
	% Color space substitution in PDF is handled somewhat differently
419
	% than in PostScript. A given device color space will be substituted
420
	% if the corresponding "Default..." entry exists in the Page's
421
	% Resource dictionary (which might be inhereted); there is no
422
	% UseCIEColor to enable/disable color mapping.
423
	%
424
	% This behavior is achieved by always setting UseCIEColor to true
425
	% in the page device dictionary. If the value of this parameter was
426
	% originally false (i.e.: the output device does not perform color
427
	% space substitution by default), the instances DefaultGray,
428
	% DefaultRGB, and DefaultCMYK of the (local) ColorSpace category
429
	% are redefined to be DeviceGray, DeviceRGB, and DeviceCMYK,
430
	% respectively. This is not done if UseCIEColor is true by default,
431
	% as in that case color substitution is presumably desired even
432
	% if the file does not request it.
433
   currentpagedevice /UseCIEColor .knownget dup { pop } if not
434
    { .currentglobal false .setglobal
435
      /DefaultGray { /DeviceGray } cvlit /ColorSpace defineresource pop
436
      /DefaultRGB { /DeviceRGB } cvlit /ColorSpace defineresource pop
437
      /DefaultCMYK { /DeviceCMYK } cvlit /ColorSpace defineresource pop
438
      .setglobal
439
    }
440
   if
441
  pdfopenfile begin
442
  pdfopencache
443
  .writepdfmarks {
444
	% Copy bookmarks (outline) to the output.
445
    Trailer /Root oget /Outlines knownoget {
446
      /First knownoget {
447
	{ dup writeoutline /Next knownoget not { exit } if } loop
448
      } if
449
    } if
450
  } if		% end .writepdfmarks
451
  currentdict end
452
} bind def
453
 
454
% Verify that each entry in the xref table is pointing at an object with
455
% the correct object number and generation number.
456
/verify_xref				% - verify_xref -
457
{ 1 1 Objects llength 1 sub		% stack: 1 1 <number of objects - 1>
458
  {	% Check if the object is free (i.e. not used).  The values in
459
	% Generations is the generation number plus 1.  If the value in
460
	% Generations is zero then the object is free.
461
    Generations 1 index lget 		% Get the genration number
462
 
463
      ObjectStream 1 index lget 	% Check if object is in objectstream
464
 
465
        {	% Use stop context since we may get an error if object is invalid
466
          dup Objects exch lget 	% Get the object location
467
	  PDFoffset add PDFfile exch setfileposition
468
	  true				% Stack:  <obj num> <true>
469
	  PDFfile token pop		% Read object number from file
470
	  2 index eq {			% Verify object number
471
	    PDFfile token pop		% Read generation number from file
472
	    Generations 3 index		% Get specified generaton number
473
	    lget 1 sub			% Gen numbs are stored with 1 added.
474
	    eq { 			% Verify generation number
475
	      PDFfile token pop /obj eq { % Verify 'obj' text
476
		pop false		% We have valid object, do not rebuild
477
	      } if
478
	    } if
479
	  } if
480
	} .internalstopped
481
	{ true } if			% If we stop then we need to rebuild
482
	{ 
483
	  (   **** Warning:  File has an invalid xref entry:  )
484
	  pdfformaterror
485
	  pdfstring cvs pdfformaterror
486
	  (.  Rebuilding xref table.\n) pdfformaterror
487
	  search_objects
488
	  exit
489
	} if				% If the entry is invalid
490
      } if				% If not in an object stream
491
    } if				% If object entry is not free
492
    pop					% Remove object number
493
  } for
494
} bind odef
495
 
496
/pdfopencache {		% - pdfopencache -
497
	% Create and initialize some caches.
498
  /PageCount pdfpagecount def
499
  /PageNumbers PageCount 65534 .min dict def
500
  /PageIndex PageCount 65534 .min array def
501
} bind def
502
 
503
/pdfopenfile {		% <file> pdfopenfile <dict>
504
   pdfdict readonly pop		% can't do it any earlier than this
505
   15 dict begin
506
   /LocalResources 0 dict def
507
   /DefaultQstate //null def	% establish binding
508
   /Printed where { pop } {
509
		% Guess whether the output device is a printer.
510
     /Printed currentpagedevice /OutputFile known def
511
   } ifelse
512
   /PSLevel1 where { pop } { /PSLevel1 false def } ifelse
513
   % NB: PDFfile is used outside of the PDF code to determine that a
514
   % PDF job is being processed; to not change or hide this key.
515
   cvlit /PDFfile exch def
516
   /PDFsource PDFfile def
517
   /Repaired false def
518
   currentglobal true .setglobal globaldict begin
519
   /TTFWarnList 0 dict def /UndefProcList 0 dict def
520
   end .setglobal
521
   PDFfile dup 0 setfileposition pdfstring readstring 
522
   not {/pdfopen cvx /syntaxerror signalerror} if
523
   (%PDF-) search not {/pdfopen cvx /syntaxerror signalerror} if
524
   length /PDFoffset exch def pop
525
   % some badly formed PDF's (Visioneer) have something other than EOL
526
   % after the version number. If we get an error, shorten the string
527
   % and try again.
528
   false exch		% error encountered
529
   { { cvr } stopped
530
     { exch pop true exch 0 1 index length 1 sub dup 0 eq
531
       { pop 0 exit } if	% exit if string now empty
532
       getinterval		% trim character from right end and retry
533
     }
534
     { exch {
535
         (   **** Warning: PDF version number not followed by EOL.\n)
536
         pdfformaterror
537
       }
538
       if exit
539
     }
540
     ifelse
541
   } loop
542
 
543
   /PDFversion exch def
544
	% Read the last cross-reference table.
545
   count /pdfemptycount exch def
546
   /Trailer << >> def		% Initialize to an emptry dict.
547
   { initPDFobjects findxref readxref } .internalstopped {
548
     recover_xref_data		% Read failed.  Attempt to recover xref data.
549
     search_trailer		% Search for the primary trailer
550
   } {
551
     /Trailer exch def		% Save trailer dict after first xref table
552
	% Read any previous cross-reference tables.  When we are done,
553
	% verify that the entries in the xref tables are valid if NoVerifyXref
554
	% is not defined.
555
     Trailer
556
     { /Prev knownoget not {	% If no previous xref table then ...
557
         /NoVerifyXref where { pop } { verify_xref } ifelse exit
558
       } if
559
       { readxref } .internalstopped {
560
         recover_xref_data	% Read failed.  Attempt to recover xref data.
561
	 exit			% Exit loop since recover gets all obj data.
562
       } if  			% If readxref stopped
563
       % The PDF spec. says that each trailer dict should contain the required
564
       % entries.  However we have seen a PDF file that only has a Prev entry in
565
       % the initial trailer dict.  Acrobat complains but it accepts these files.
566
       % To work with these files, we are copying any entries which we find in
567
       % a previous trailer dict which are not present in the initial dict.
568
       dup {
569
         Trailer 2 index known {
570
           pop pop              % discard if key already present
571
         } {
572
           Trailer 3 1 roll put % add key if not present
573
         } ifelse
574
       } forall
575
     } loop			% Loop to previous trailer
576
   } ifelse			% Ifelse readxref stopped
577
   Trailer /Encrypt knownoget {
578
     pop
579
     pdf_process_Encrypt	% signal error
580
   } if
581
   currentdict end
582
 } bind def
583
 
584
% Look for [\r\n]%%EO from the current position of the file.
585
% Return the position of %%EO if found or -1 .
586
/findeof {  % <file> find_eof <file> <position>
587
  -1 exch
588
  {
589
    dup bytesavailable 4 lt { exit } if
590
    dup 0 (%%EO) /SubFileDecode filter flushfile
591
    dup dup fileposition 5 sub setfileposition
592
    dup 5 string readstring not { pop exit } if
593
    dup (\r%%EO) eq exch (\n%%EO) eq or {
594
      dup fileposition 4 sub
595
      3 1 roll exch pop
596
    } if
597
  } loop
598
  exch
599
} bind def
600
 
601
% Skip backward over the %%EOF at the end of the PDF file, and read
602
% the preceding startxref line.  The PDF specification unambiguously
603
% requires that the %%EOF appear on a line by itself, and that the
604
% startxref and the following position value appear on separate lines;
605
% however, some applications truncate the %%EOF to %%EO, and/or put the
606
% startxref and the following value on the same line.
607
% There seems to be no limit on the amount of garbage that can be
608
% appended to the PDF file. Current record (60K) belongs to
609
% PDF-Out (v 2.0 - 35). We start the search for %%EO from the last 1024
610
% bytes and continue from the beginning of the file.
611
/findxref {		% - findxref <xrefpos>
612
  PDFfile dup dup dup 0 setfileposition bytesavailable
613
  dup /PDFfilelen exch def
614
	% Find the last %%EOF string (within 1024 bytes)
615
  1024 sub PDFoffset .max
616
  setfileposition findeof                  % search the last 1024 bytes
617
  dup 0 le {
618
    pop
619
    dup PDFoffset setfileposition findeof  % search from the beginnibg
620
    dup 0 le {
621
       (   **** Error: Cannot find a %%EOF marker anywhere in the file.\n)
622
       pdfformaterror
623
       /findxref cvx /syntaxerror signalerror
624
    } if
625
  } if
626
  dup 3 1 roll setfileposition
627
        % Stack: eofpos
628
	% Check for whether this is, in fact, a valid PDF file.
629
  dup PDFfilelen exch sub dup dup 7 gt exch 5 lt or {
630
    pop true
631
  } {
632
    string PDFfile exch readstring pop
633
    dup (%%EOF\n) eq exch dup (%%EOF\r) eq
634
    exch dup (%%EOF\r\n) eq exch (%%EOF) eq or or or not
635
  } ifelse {
636
    (   **** Warning: File has a corrupted %%EOF marker, or garbage after %%EOF.\n)
637
    pdfformaterror
638
  } if
639
  PDFfile exch setfileposition
640
	% Now read the startxref and xref start position.
641
  prevline token not { null } if dup type /integertype eq {
642
    exch pop cvi		% xref start position
643
    exch PDFfile exch setfileposition
644
    prevline dup (startxref) linene {
645
      % startxref not on a line by itself.  We have found PDF from
646
      % www.verypdf.com in which the startxref was on the same line as
647
      % the end of trailer dictionary.  Check for this.  Note:  This
648
      % violates the spec.
649
      dup (startxref) search {
650
	% found startxref - print warning
651
	pop pop pop 			% clear strings from search
652
        (   **** Warning: format of the startxref line in this file is invalid.\n)
653
        pdfformaterror
654
      } {				% no startxref - we have a problem.
655
        /findxref cvx /syntaxerror signalerror
656
      } ifelse
657
    } if
658
    pop pop
659
  } {	% else, this file has 'startxref #####' format
660
    (startxref) ne { /findxref cvx /syntaxerror signalerror } if
661
    cvi		% xref start position
662
    (   **** Warning: format of the startxref line in this file is invalid.\n)
663
    pdfformaterror
664
    exch PDFfile exch setfileposition
665
  } ifelse
666
} bind def
667
/stderrfile (%stderr) (w) file def
668
/stderrprint {                % <string> stderrprint -
669
  //stderrfile dup 3 -1 roll writestring flushfile
670
} bind def
671
/pdfformaterror {	% <string> pdfformaterror -
672
  stderrprint
673
  /Repaired true store
674
} bind def
675
 
676
/knownoget_safe
677
{ 2 copy knownoget { 3 1 roll pop pop //true } { pop pop //false } ifelse
678
} odef
679
 
680
/printProducer {
681
  Trailer /Info { knownoget_safe } stopped { pop pop false } if {
682
    /Producer knownoget not { null } if
683
  } {
684
    null
685
  } ifelse
686
  dup null eq {
687
    pop
688
  } {
689
    (   **** The file was produced by: \n   **** >>>> ) stderrprint
690
	% Handle a Unicode Producer.
691
    (\376\377) anchorsearch {
692
      pop dup length 2 idiv string 0 1 2 index length 1 sub {
693
		% Stack: origstr newstr i
694
	1 index exch 3 index 1 index 2 mul 1 add get put
695
      } for exch pop
696
    } if
697
    stderrprint
698
    ( <<<<\n) stderrprint
699
  } ifelse
700
} bind def
701
% The TTFWarnList is the list of all TrueType fonts that were not embedded.
702
% The UndefProcList collects noisy warnings.
703
% This gets rid of many multiple warnings from pdf_font.ps
704
/printCollectedWarnings {
705
   TTFWarnList length 0 gt {
706
      (\n   **** Warning: Fonts with Subtype = /TrueType should be embedded.\n)
707
      stderrprint
708
      (                 The following fonts were not embedded:\n)
709
      stderrprint
710
      [ TTFWarnList { pop .namestring (\t\t\t) exch concatstrings (\n) concatstrings } forall ] 
711
      { lt } .sort { stderrprint } forall
712
   } if
713
   UndefProcList length 0 gt {
714
      (\n   **** Embedded font uses undefined procedure\(s\):  ) stderrprint
715
      UndefProcList {
716
         exch .namestring stderrprint ( ) stderrprint
717
	 =string cvs stderrprint ( times, ) stderrprint
718
      } forall 
719
      (\n) stderrprint
720
   } if
721
} bind def
722
/printrepaired {
723
   printCollectedWarnings
724
   (\n   **** This file had errors that were repaired or ignored.\n)
725
  stderrprint
726
  printProducer
727
  (   **** Please notify the author of the software that produced this\n)
728
  stderrprint
729
  (   **** file that it does not conform to Adobe's published PDF\n)
730
  stderrprint
731
  (   **** specification.\n\n)
732
  stderrprint
733
} bind def
734
 
735
% Write the outline structure for a file.  Uses linkdest (below).
736
% omit links to pages that don't exist.
737
/writeoutline		% <outlinedict> writeoutline -
738
 { mark
739
 
740
    { { exch 1 add exch /Next knownoget not { exit } if } loop }
741
   if
742
		% stack: dict mark count
743
   dup 0 eq
744
    { pop 1 index }
745
    { 2 index /Count knownoget { 0 lt { neg } if } if
746
      /Count exch 3 index
747
    }
748
   ifelse { linkdest } stopped 
749
    {
750
      cleartomark	% ignore this link
751
      (   **** Warning: Outline has invalid link that was discarded.\n)
752
      pdfformaterror
753
    } {
754
      /Title oget /Title exch /OUT pdfmark
755
    }
756
   ifelse
757
   /First knownoget
758
    { { dup writeoutline /Next knownoget not { exit } if } loop }
759
   if
760
 } bind def
761
 
762
% Close a PDF file.
763
/pdfclose		% <dict> pdfclose -
764
 { begin
765
   PDFfile closefile
766
   end
767
 } bind def
768
 
769
% ======================== Page accessing ======================== %
770
 
771
% Get a (possibly inherited) attribute of a page.
772
/pget			% <pagedict> <key> pget <value> -true-
773
			% <pagedict> <key> pget -false-
774
 { 2 copy knownoget
775
    { exch pop exch pop true
776
    }
777
    { exch /Parent knownoget
778
       { exch pget }
779
       { pop false }
780
      ifelse
781
    }
782
   ifelse
783
 } bind def
784
 
785
% Get the value of a resource on a given page.
786
/rget {			% <resname> <pagedict> <restype> rget <value> -true-
787
			% <resname> <pagedict> <restype> rget -false-
788
  LocalResources 1 index knownoget {
789
     3 index knownoget
790
  } {
791
    false
792
  } ifelse {
793
    exch pop exch pop exch pop true
794
  } {
795
    exch /Resources pget {
796
      exch knownoget { exch knownoget } { pop false } ifelse
797
    } {
798
      pop pop false
799
    } ifelse
800
  } ifelse
801
} bind def
802
 
803
% Get the total number of pages in the document.
804
/pdfpagecount		% - pdfpagecount <int>
805
 { Trailer /Root oget /Pages oget /Count oget
806
 } bind def
807
 
808
% Find the N'th page of the document by iterating through the Pages tree.
809
% The first page is numbered 1.
810
/pdffindpageref {		% <int> pdffindpage <objref>
811
  dup Trailer /Root oget /Pages get
812
    {		% We should be able to tell when we reach a leaf
813
		% by finding a Type unequal to /Pages.  Unfortunately,
814
		% some files distributed by Adobe lack the Type key
815
		% in some of the Pages nodes!  Instead, we check for Kids.
816
      dup oforce /Kids knownoget not { exit } if
817
      exch pop null
818
 
819
         2 index exch get
820
	 dup oforce dup /Kids known { /Count oget } { pop 1 } ifelse
821
		% Stack: index kids null noderef count
822
	 dup 5 index ge { pop exch pop exit } if
823
	 5 -1 roll exch sub 4 1 roll pop
824
      } for exch pop
825
		% Stack: index null|noderef
826
      dup null eq { pop pop 1 null exit } if
827
    } loop
828
		% Stack: index countleft noderef
829
   1 index 1 ne { pop pop /pdffindpage cvx /rangecheck signalerror } if
830
   exch pop
831
   PageIndex 2 index 1 sub 65533 .min 2 index oforce put
832
   PageNumbers 1 index oforce 3 index dup 65534 le
833
    { put }
834
    { pop pop pop }	% don't store more than 65534 pagenumbers
835
   ifelse
836
   exch pop
837
} bind def
838
/pdffindpage {		% <int> pdffindpage <pagedict>
839
  pdffindpageref oforce
840
} bind def
841
 
842
% Find the N'th page of the document.
843
% The first page is numbered 1.
844
/pdfgetpage		% <int> pdfgetpage <pagedict>
845
 { PageIndex 1 index 1 sub dup 65533 lt
846
    { get }
847
    { pop pop null }
848
   ifelse
849
   dup null ne
850
    { exch pop oforce }
851
    { pop pdffindpage }
852
   ifelse
853
 } bind def
854
 
855
% Find the page number of a page object (inverse of pdfgetpage).
856
/pdfpagenumber		% <pagedict> pdfpagenumber <int>
857
 {	% We use the simplest and stupidest of all possible algorithms....
858
   PageNumbers 1 index .knownget
859
    { exch pop
860
    }
861
    { 1 1 PageCount 1 add	% will give a rangecheck if not found
862
       { dup pdfgetpage oforce 2 index eq { exit } if pop
863
       }
864
      for exch pop
865
    }
866
   ifelse
867
 } bind def
868
 
869
% Arrange the four elements that define a rectangle into a 'normal' order.
870
/normrect_elems   % <x1> <y1> <x2> <y2> normrect_elems <llx> <lly> <urx> <ury>
871
{
872
    exch 4 1 roll			% <x2> <x1> <y1> <y2>
873
    2 copy gt { exch } if		% <x2> <x1> <lly> <ury>
874
    4 2 roll 2 copy lt { exch } if	% <lly> <ury> <urx> <llx>
875
    4 1 roll exch			% <llx> <lly> <urx> <ury>
876
} bind def
877
 
878
% Arrange a rectangle into a 'normal' order.  I.e the lower left corner
879
% followed by the upper right corner.
880
/normrect 	% <rect> normrect <rect>
881
{
882
    aload pop normrect_elems 4 array astore
883
} bind def
884
 
885
/boxrect		% <llx> <lly> <urx> <ury> boxrect <x> <y> <w> <h>
886
 { exch 3 index sub exch 2 index sub
887
 } bind def
888
/resolvedest {		% <name|string|other> resolvedest <other|null>
889
  dup type /nametype eq {
890
    Trailer /Root oget /Dests knownoget {
891
      exch knownoget not { null } if
892
    } {
893
      pop null
894
    } ifelse
895
  } {
896
    dup type /stringtype eq {
897
      Trailer /Root oget /Names knownoget {
898
	/Dests knownoget {
899
	  exch nameoget
900
	} {
901
	  pop null
902
	} ifelse
903
      } {
904
	pop null
905
      } ifelse
906
    } if
907
  } ifelse
908
} bind def
909
/linkdest {		% <link|outline> linkdest
910
			%   ([/Page <n>] /View <view> | ) <link|outline>
911
  dup /Dest knownoget
912
    { resolvedest
913
      dup type /dicttype eq { /D knownoget not { null } if } if
914
      dup null eq
915
       { pop }
916
       { dup 0 oget
917
         dup type /dicttype eq {
918
           dup /Type knownoget {
919
             /Page eq {
920
               pdfpagenumber
921
             } if
922
           } if
923
         } if
924
         dup type /integertype ne 
925
           { pop }
926
           { /Page exch 4 -2 roll }
927
         ifelse
928
	 dup length 1 sub 1 exch getinterval /View exch 3 -1 roll
929
       }
930
      ifelse
931
    }
932
   if
933
} bind def
934
% <pagedict> mark ... -proc- -
935
/namedactions 8 dict dup begin
936
  /FirstPage {
937
    /Page 1 3 -1 roll
938
  } def
939
  /LastPage {
940
    counttomark 2 add index pdfpagecount /Page exch 3 -1 roll
941
  } def
942
  /NextPage {
943
    counttomark 2 add index pdfpagenumber 1 add /Page exch 3 -1 roll
944
  } def
945
  /PrevPage {
946
    counttomark 2 add index pdfpagenumber 1 sub /Page exch 3 -1 roll
947
  } def
948
end readonly def
949
% <pagedict> <annotdict> -proc- -
950
/annottypes 5 dict dup begin
951
  /Text {
952
    mark exch
953
     { /Rect /Open /Contents }
954
     { 2 copy knownoget { 3 -1 roll } { pop } ifelse }
955
    forall pop /ANN pdfmark
956
  } bind def
957
  /Link {
958
    mark exch
959
    dup /C knownoget { /Color exch 3 -1 roll } if
960
     { /Rect /Border }
961
     { 2 copy knownoget { 3 -1 roll } { pop } ifelse }
962
    forall dup /A knownoget {
963
      dup /URI known {
964
        /A mark 3 2 roll    % <<>> /A [ <<action>>
965
        { oforce } forall
966
        .dicttomark
967
        3 2 roll
968
      } {
969
        dup /D knownoget {
970
	  exch pop exch dup length dict copy dup /Dest 4 -1 roll put
971
        } {
972
	  /N knownoget {		% Assume /S /Named
973
	     namedactions exch .knownget { exec } if
974
	  } if
975
        } ifelse
976
      } ifelse
977
    } if
978
    linkdest pop /LNK pdfmark
979
  } bind def
980
end readonly def
981
 
982
% **** The following procedure should not be changed to allow clients
983
% **** to directly interface with the constituent procedures. GSview
984
% **** and some Artifex customers rely on the pdfshowpage_init,
985
% **** pdfshowpage_setpage, pdfshowpage_finish so all logic should be
986
% **** implemented in one of those three procedures.
987
/pdfshowpage		% <pagedict> pdfshowpage -
988
 { dup /Page exch store
989
   pdfshowpage_init 
990
   pdfshowpage_setpage 
991
   pdfshowpage_finish
992
 } bind def
993
 
994
/pdfpagecontents	% <pagedict> pdfpagecontents <contents>
995
 { } bind def
996
 
997
/pdfshowpage_init 	% <pagedict> pdfshowpage_init <pagedict>
998
 { /DSCPageCount DSCPageCount 1 add store
999
 } bind def
1000
 
1001
/.pdfshowpage_Install {	% <pagedict> [<prevproc>] .pdfshowpage_Install -
1002
  exch
1003
	% We would like to clip to the CropBox here, but the subsequent
1004
	% initgraphics would override it.  Instead, we have to handle it
1005
	% in graphicsbeginpage.
1006
  dup /CropBox pget dup {exch pop} if systemdict /UseCropBox known and {
1007
    dup /CropBox pget pop
1008
  } {
1009
    dup /MediaBox pget pop	% There has to be a MediaBox
1010
  } ifelse
1011
  % stack: [<prevproc>] <pagedict> <Crop|Media Box>
1012
  exch pop oforce_array normrect		% done with the pagedict
1013
  systemdict /PDFFitPage known {
1014
    PDFDEBUG { (Fiting PDF to imageable area of the page.) = flush } if
1015
    currentpagedevice /.HWMargins get aload pop
1016
    currentpagedevice /PageSize get aload pop
1017
    3 -1 roll sub 3 1 roll exch sub exch
1018
    % stack: [<prevproc>] <pagedict> <Crop|Media Box> Xmin Ymin Xmax Ymax
1019
    PDFDEBUG { (    Translate up by [ ) print 3 index =print (, ) print 2 index =print ( ]) = flush } if
1020
    3 index 3 index translate		% move origin up to imageable area
1021
    2 index sub exch 3 index sub exch 4 2 roll pop pop
1022
	    % stack: [Box] XImageable YImageable
1023
    2 index aload pop 2 index sub exch 3 index sub exch 4 2 roll pop pop
1024
	    % stack: [Box] XImageable YImageable XBox YBox
1025
    3 -1 roll exch div 3 1 roll div .min
1026
    PDFDEBUG { (    Scale by ) print dup = flush } if
1027
    dup scale
1028
  } if
1029
  % Now translate to the origin given in the Crop|Media Box
1030
  dup 0 get neg exch 1 get neg translate
1031
 
1032
  exec
1033
} bind def
1034
 
1035
/pdfshowpage_setpage {	% <pagedict> pdfshowpage_setpage <pagedict>
1036
  5 dict begin		% for setpagedevice
1037
	% Stack: pagedict
1038
  % UseCIEColor is always true for PDF; see the comment in runpdf above
1039
  /UseCIEColor true def
1040
  currentpagedevice /Orientation 2 index /Rotate pget not { 0 } if 90 idiv
1041
	% Rotate specifies *clockwise* rotation!
1042
    neg 3 and def
1043
	% Stack: pagedict currentpagedict
1044
  1 index /CropBox pget dup {exch pop} if systemdict /UseCropBox known and {
1045
			% Set the page size.
1046
    1 index /CropBox pget pop oforce_elems normrect_elems boxrect
1047
    2 array astore /PageSize exch def pop pop
1048
  } {
1049
    1 index /MediaBox pget {
1050
			% Set the page size.
1051
      oforce_elems normrect_elems boxrect
1052
      2 array astore /PageSize exch def pop pop
1053
    } if
1054
  } ifelse
1055
  % Don't change the page size if we are going to fit the PDF to the page
1056
  systemdict /PDFFitPage known { currentdict /PageSize undef } if
1057
  % Let the device know if we will be using PDF 1.4 transparency.
1058
  % The clist logic may need to adjust the size of bands.
1059
  1 index pageusestransparency /PageUsesTransparency exch def
1060
  dup /Install .knownget {
1061
			% Don't let the Install procedure get more deeply
1062
			% nested after every page.
1063
      dup type dup /arraytype eq exch /packedarraytype eq or {
1064
	dup length 4 eq {
1065
	  dup 2 get /.pdfshowpage_Install load eq {
1066
	    1 get 0 get	% previous procedure
1067
	  } if
1068
	} if
1069
      } if
1070
  } {
1071
    { }
1072
  } ifelse 1 array astore
1073
  2 index exch /.pdfshowpage_Install load /exec load
1074
  4 packedarray cvx
1075
	% Stack: pagedict currentpagedict installproc
1076
  /Install exch def
1077
	% Stack: pagedict currentpagedict
1078
  pop currentdict end setpagedevice
1079
} bind def
1080
 
1081
/pdfshowpage_finish {	% <pagedict> pdfshowpage_finish -
1082
   save /PDFSave exch store
1083
   /PDFdictstackcount countdictstack store
1084
   (before exec) VMDEBUG
1085
 
1086
   % set up color space substitution (this must be inside the page save)
1087
   pdfshowpage_setcspacesub
1088
 
1089
  .writepdfmarks {
1090
 
1091
	% Copy the crop box.
1092
    dup /CropBox knownoget {
1093
      oforce_array normrect
1094
 
1095
        % .pdfshowpage_Install translates the origin -
1096
        % do same here with the CropBox.
1097
 
1098
      1 index /CropBox pget dup {exch pop} if systemdict /UseCropBox known and {
1099
        1 index /CropBox pget pop
1100
      } {
1101
        1 index /MediaBox pget pop	% There has to be a MediaBox
1102
      } ifelse
1103
      oforce_array normrect
1104
      dup 0 get exch 1 get   % [] tx ty
1105
      2 index 0 get 2 index sub 3 index exch 0 exch put
1106
      2 index 2 get 2 index sub 3 index exch 2 exch put
1107
      2 index 1 get 1 index sub 3 index exch 1 exch put
1108
      2 index 3 get 1 index sub 3 index exch 3 exch put
1109
      pop pop
1110
 
1111
	% If the page has been rotated, rotate the CropBox.
1112
      mark /CropBox 3 -1 roll
1113
      3 index /Rotate pget {
1114
	90 idiv 1 and 0 ne {
1115
	  aload pop 4 -2 roll exch 4 2 roll exch 4 array astore
1116
	} if
1117
      } if
1118
      /PAGE pdfmark
1119
    } if
1120
 
1121
	% Copy annotations and links.
1122
    dup /Annots knownoget {
1123
 
1124
       { 1 index exch oget
1125
         dup /Subtype oget annottypes exch .knownget { exec } { pop } ifelse
1126
       }
1127
      for pop
1128
    } if
1129
 
1130
  } if		% end .writepdfmarks
1131
 
1132
	% Display the actual page contents.
1133
   6 dict begin
1134
   /BXlevel 0 def
1135
   /BGDefault currentblackgeneration def
1136
   /UCRDefault currentundercolorremoval def
1137
	%****** DOESN'T HANDLE COLOR TRANSFER YET ******
1138
   /TRDefault currenttransfer def
1139
  matrix currentmatrix 2 dict
1140
  2 index /CropBox knownoget {
1141
    oforce_elems normrect_elems boxrect
1142
    4 array astore 1 index /ClipRect 3 -1 roll put
1143
  } if
1144
  dictbeginpage setmatrix
1145
  /DefaultQstate qstate store
1146
 
1147
  dup		  % for showing annotations below
1148
  count 1 sub /pdfemptycount exch store
1149
	% If the page uses any transparency features, show it within
1150
	% a transparency group.
1151
  dup pageusestransparency dup /PDFusingtransparency exch def {
1152
    % Show the page within a PDF 1.4 device filter.
1153
 
1154
      /DefaultQstate qstate store		% device has changed -- reset DefaultQstate
1155
      % If the page has a Group, enclose contents in transparency group.
1156
      % (Adobe Tech Note 5407, sec 9.2)
1157
      dup /Group knownoget {
1158
	1 index /CropBox knownoget not {
1159
	  1 index /MediaBox pget pop
1160
	} if oforce_array normrect .beginformgroup {
1161
	  showpagecontents
1162
	} stopped {
1163
	  .discardtransparencygroup stop
1164
	} if .endtransparencygroup
1165
      } {
1166
	showpagecontents
1167
      } ifelse
1168
    } stopped {
1169
      % todo: discard
1170
      .poppdf14devicefilter 
1171
      /DefaultQstate qstate store	% device has changed -- reset DefaultQstate
1172
      stop
1173
    } if .poppdf14devicefilter
1174
    /DefaultQstate qstate store	% device has changed -- reset DefaultQstate
1175
  } {
1176
    showpagecontents
1177
  } ifelse
1178
  % check for extra garbage on the ostack and clean it up
1179
  count pdfemptycount sub dup 0 ne {
1180
    (   **** File did not complete the page properly and may be damaged.\n)
1181
    pdfformaterror
1182
    { pop } repeat
1183
  } {
1184
    pop
1185
  } ifelse
1186
  % todo: mixing drawing ops outside the device filter could cause
1187
  % problems, for example with the pnga device.
1188
  /Annots knownoget { { oforce drawannot } forall } if
1189
  endpage
1190
  end			% scratch dict
1191
  % Some PDF files don't have matching q/Q (gsave/grestore) so we need
1192
  % to clean up any left over dicts from the dictstack
1193
  countdictstack PDFdictstackcount sub dup 0 ne { 
1194
    (   **** Warning: File has imbalanced q/Q operators \(too many q's\)\n)
1195
    pdfformaterror
1196
    { end } repeat
1197
  } {
1198
    pop
1199
  } ifelse
1200
  (after exec) VMDEBUG
1201
  Repaired		% pass Repaired state around the restore
1202
  PDFSave restore
1203
  /Repaired exch def
1204
} bind def
1205
/showpagecontents {	% <pagedict> showpagecontents -
1206
  gsave		% preserve gstate for Annotations later
1207
  /Contents knownoget not { 0 array } if
1208
  dup type /arraytype ne { 1 array astore } if {
1209
    oforce false resolvestream pdfopdict .pdfrun
1210
  } forall
1211
  grestore
1212
} bind def
1213
/processcolorspace {	% - processcolorspace <colorspace>
1214
	% The following is per the PLRM3.
1215
  currentdevice 1 dict dup /ProcessColorModel dup put .getdeviceparams
1216
  exch pop exch pop
1217
  dup type /nametype ne { cvn } if
1218
  dup { setcolorspace } .internalstopped { pop /DeviceRGB } if
1219
} bind def
1220
 
1221
% ------ Transparency support ------ %
1222
 
1223
% Define minimum PDF version for checking for transparency features.
1224
% Transparency is a 1.4 feature however we have seen files that claimed
1225
% to be PDF 1.3 with transparency features.
1226
/PDFtransparencyversion 1.3 def
1227
 
1228
% Determine whether a page might invoke any transparency features:
1229
%	- Non-default BM, ca, CA, or SMask in an ExtGState
1230
%	- Image XObject with SMask
1231
% Note: we deliberately don't check to see whether a Group is defined,
1232
% because Adobe Illustrator 10 (and possibly other applications) define
1233
% a page-level group whether transparency is actually used or not.
1234
% Ignoring the presence of Group is justified because, in the absence
1235
% of any other transparency features, they have no effect.
1236
/pageusestransparency {		% <pagedict> pageusestransparency <bool>
1237
  PDFversion PDFtransparencyversion lt NOTRANSPARENCY or {
1238
    pop false
1239
  } {
1240
    false exch {
1241
      4 dict 1 index resourceusestransparency { pop not exit } if
1242
      /Parent knownoget not { exit } if
1243
    } loop
1244
  } ifelse
1245
} bind def
1246
 
1247
% Check the Resources of a page or Form. Check for loops in the resource chain.
1248
/resourceusestransparency {	% <dict> <dict> resourceusestransparency <bool>
1249
  {	% Use loop to provide an exitable context.
1250
    /Resources knownoget not { 0 dict } if
1251
    2 copy known {
1252
      (   **** File has circular references in resource dictionaries.\n)
1253
      pdfformaterror
1254
      pop false exit
1255
    } if
1256
    2 copy dup put
1257
    dup /ExtGState knownoget {
1258
      false exch {
1259
	exch pop oforce
1260
	dup /BM knownoget { dup /Normal ne exch /Compatible ne and
1261
	                    { pop not exit } if
1262
                          } if
1263
	dup /ca knownoget { 1 ne { pop not exit } if } if
1264
	dup /CA knownoget { 1 ne { pop not exit } if } if
1265
	dup /SMask knownoget { /None ne { pop not exit } if } if
1266
	pop
1267
      } forall { pop true exit } if
1268
    } if
1269
    dup /XObject knownoget {
1270
      false exch {
1271
	exch pop oforce dup /Subtype get
1272
	dup /Image eq { 1 index /SMask known { pop pop not exit } if } if
1273
	/Form eq {
1274
	  3 index exch resourceusestransparency { not exit } if
1275
	} {
1276
	  pop
1277
	} ifelse
1278
      } forall { pop true exit } if
1279
    } if
1280
    pop false exit
1281
  } loop
1282
  exch pop
1283
} bind def
1284
 
1285
% ------ ColorSpace substitution support ------ %
1286
 
1287
%
1288
%  <pagedict>   pdfshowpage_setcspacesub   <pagedict>
1289
%
1290
% Set up color space substitution for a page. Invocations of this procedure
1291
% must be bracketed by the save/restore operation for the page, to avoid
1292
% unintended effects on other pages.
1293
%
1294
% If any color space substitution is used, and the current color space is a
1295
% device dependent color space, make sure the current color space is updated.
1296
% There is an optimization in the setcolorspace pseudo-operator that does
1297
% nothing if both the current and operand color spaces are the same. For
1298
% PostScript this optimization is disabled if the UseCIEColor page device
1299
% parameter is true. This is not the case for PDF, as performance suffers
1300
% significantly on some PDF files if color spaces are set repeatedly. Hence,
1301
% if color space substitution is to be used, and the current color space
1302
% is a device dependent color space, we must make sure to "transition" the
1303
% current color space.
1304
%
1305
/pdfshowpage_setcspacesub
1306
  {
1307
    false
1308
      { /DefaultGray /DefaultRGB /DefaultCMYK }
1309
      {
1310
        dup 3 index /ColorSpace //rget exec
1311
          { resolvecolorspace /ColorSpace defineresource pop }
1312
          { pop }
1313
        ifelse
1314
      }
1315
    forall
1316
 
1317
    % if using color space substitution, "transition" the current color space
1318
      {
1319
        currentcolorspace dup length 1 eq   % always an array
1320
          {
1321
 
1322
            dup /DeviceGray eq 1 index /DeviceRGB eq or 1 index /DeviceCMYK or
1323
              { /Pattern setcolorspace setcolorspace }
1324
              { pop }
1325
            ifelse
1326
          }
1327
          { pop }
1328
        if
1329
      }
1330
    if
1331
  }
1332
bind def
1333
 
1334
 
1335
 
1336
end			% pdfdict
1337
.setglobal