123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- % Copyright (C) 1999, 2000, 2001 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: pdfwrite.ps,v 1.7 2001/07/30 07:16:32 lpd Exp $
- % Writer for transmuting PDF files.
- % NOTES:
- % We do editing by replacing objects (in the cache) and then doing a
- % simple recursive walk with object renumbering.
- % Free variables:
- % RMap [per input file] (dict): input_obj# => output_obj#
- % PDFfile (file): current input file
- % OFile (file): current output file
- % XRef (dict): output_obj# => output_file_pos
- % ToWrite: 0..N-1 => [obj# gen#]
- /.setlanguagelevel where { pop 2 .setlanguagelevel } if
- .currentglobal true .setglobal
- /PDEBUG where { pop } { /PDEBUG false def } ifelse
- % ================ Object mapping ================ %
- % Initialize the object number and location map.
- /omapinit { % - omapinit -
- /RMap 100 dict def
- /XRef 100 dict def
- PDEBUG { (omapinit) = } if
- } def
- % Map an object number.
- /omapnew { % <oldobj#> omap <newobj#> <isnew>
- RMap 1 index .knownget {
- exch pop false
- } {
- PDEBUG { (omap\() print dup =only } if
- RMap dup length 1 add 2 index exch dup 5 1 roll put pop true
- PDEBUG { (\) = ) print 1 index = } if
- } ifelse
- } def
- /omap { % <oldobj#> omap <newobj#>
- omapnew pop
- } bind def
- % Save and restore the object map.
- % Note that currentomap either returns a copy or calls omapinit.
- /currentomap { % <copy> currentomap <omap>
- {
- [RMap dup length dict copy XRef dup length dict copy]
- } {
- [RMap XRef] omapinit
- } ifelse
- } bind def
- /setomap { % <omap> setomap -
- aload pop /XRef exch def /RMap exch def
- PDEBUG {
- (setomap: #Xref = ) print XRef length =only
- (, #RMap = ) print RMap length =
- } if
- } bind def
- % ================ Writing ================ %
- % ---------------- Low-level output ---------------- %
- % Write a string on the output file.
- /ows { % <string> ows -
- OFile exch writestring
- } def
- % ---------------- Scalars ---------------- %
- % Note that the '#' character isn't legal in a name unless it is a prefix
- % for a hex encoded character (for PDF 1.2 and later). The following assumes
- % that the names are already valid PDF 1.2+ names so that we can treat the
- % '#' as a legal character. The next two hex characters are already in the
- % set of valid name characters. PDF 1.1 and earlier allowed spaces in names
- % which probably wouldn't make it past the tokenizer anyway.
- /pdfnamechars
- (!"#$&'*+,-.0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ\\^_`abcdefghijklmnopqrstuvwxyz|~)
- readonly def
- /pdfwritename { % <name> pdfwritename -
- (/) ows .namestring {
- ( ) dup 0 4 -1 roll put
- //pdfnamechars 1 index search {
- pop pop pop
- } {
- pop 0 get 256 add 16 =string cvrs
- dup 0 (#) 0 get put
- } ifelse ows
- } forall
- } def
- % ---------------- Composite objects ---------------- %
- /pdfwriteprocs mark
- /resolveR { pdfwriteref }
- /O { pdfwritenewref }
- .dicttomark readonly def
- /pdfwritearray { % <array> pdfwritearray -
- dup xcheck {
- aload pop //pdfwriteprocs exch get exec
- } {
- % Because of a bug in Acrobat's parser for linearization parameters,
- % we have to include some whitespace after the opening [ (!).
- ([ ) ows { pdfwritevalue (\n) ows } forall (]) ows
- } ifelse
- } def
- /pdfwritedict { % <dict> pdfwritedict -
- dup xcheck {
- pdfwritestream
- } {
- (<<) ows {
- exch pdfwritevalue ( ) ows pdfwritevalue (\n) ows
- } forall (>>) ows
- } ifelse
- } def
- % ---------------- References ---------------- %
- /pdfwritenewref { % <newobj#> pdfwritenewref -
- OFile exch write=only ( 0 R) ows
- } def
- /pdfwriteref { % <obj#> <gen#> pdfwriteref -
- 1 index omapnew {
- ToWrite dup length 5 -2 roll 2 packedarray put
- } {
- exch pop exch pop
- } ifelse
- pdfwritenewref
- } def
- /pdfcopystring 200 string def
- /pdfwritestream { % <streamdict> pdfwritestream -
- % Remove File, FilePosition, and StreamKey;
- % optimize by replacing an indirect Length.
- dup dup length dict copy
- % Stack: origdict dict
- dup /File undef dup /FilePosition undef dup /StreamKey undef
- dup /Length get dup oforce ne {
- dup /Length 2 copy oget put
- } if
- exch dup /File get dup 3 -1 roll /FilePosition get setfileposition
- pdfcopystream
- } def
- % We put copying the stream contents in separate procedures so that we
- % can replace this function if desired.
- /pdfcopybytes { % <fromfile> <tofile> <length> pdfcopybytes -
- {
- dup 0 eq { exit } if
- //pdfcopystring 0 2 index 2 index length .min getinterval
- 3 index exch readstring 3 1 roll
- 3 index 1 index writestring length sub exch not { exit } if
- } loop pop pop pop
- } def
- /pdfcopystream { % <newstreamdict> <file> pdfcopystream -
- % (file has been positioned)
- 1 index pdfwritevalue (stream\n) ows
- exch /Length get OFile exch pdfcopybytes
- (endstream) ows
- } def
- % ---------------- General values/objects ---------------- %
- /pdfwritetypes mark
- % Scalars
- /nulltype { pop (null) ows }
- /integertype { =string cvs ows }
- /booleantype 1 index
- /realtype { OFile exch write===only }
- /stringtype 1 index
- /nametype { pdfwritename }
- % Composite/reference objects
- /arraytype { pdfwritearray }
- /packedarraytype 1 index
- /dicttype { pdfwritedict }
- .dicttomark readonly def
- /pdfwritevalue { % <obj> pdfwritevalue -
- PDEBUG { (****Writing: ) print dup === flush } if
- //pdfwritetypes 1 index type get exec
- } def
- % We make pdfwriteobjdef a separate procedure for external use.
- /pdfwriteobjheader { % <newobj#> pdfwriteobjheader -
- XRef 1 index OFile .fileposition put
- PDEBUG { (XRef\() print dup =only (\) = ) print XRef 1 index get = } if
- OFile exch write=only ( 0 obj\n) ows
- } def
- /pdfwriteobjdef { % <newobj#> <value> pdfwriteobjdef -
- exch pdfwriteobjheader
- pdfwritevalue (\nendobj\n) ows
- } def
- /pdfwriteobj { % <obj#> <gen#> pdfwriteobj -
- 1 index exch resolveR exch omap exch pdfwriteobjdef
- } def
- % ---------------- File-level entities ---------------- %
- % Write a PDF file header.
- % Free variables: OFile, PDFversion.
- /pdfwriteheader { % - pdfwriteheader -
- (%PDF-) ows OFile PDFversion write=
- (%\347\363\317\323\n) ows
- } bind def
- % Write a cross-reference table and trailer.
- /pdfwritexref { % <firstobj#> <#objs> pdfwritexref -
- (xref\n) ows
- OFile 2 index write=only ( ) ows OFile 1 index write=
- 1 index add 1 sub 1 exch {
- dup 0 eq {
- pop (0000000000 65535 f \n) ows
- } {
- XRef exch get 1000000000 add =string cvs
- dup 0 (0) 0 get put
- ows ( 00000 n \n) ows
- } ifelse
- } for
- } bind def
- /pdfwritetrailer { % <trailer> pdfwritetrailer -
- (trailer\n) ows pdfwritevalue (\n) ows
- } bind def
- /pdfwritestartxref { % <startpos> pdfwritestartxref -
- (startxref\n) ows OFile exch write=
- (%%EOF\n) ows
- } bind def
- % ================ Top-level control ================ %
- /pdfwrite { % <file> <trailer> pdfwrite -
- 10 dict begin
- /trailer exch def
- /OFile exch def
- /ToWrite 100 dict def
- omapinit
- % Write the PDF file header.
- pdfwriteheader
- % Write the objects.
- trailer {
- exch pop dup xcheck { % The only executable objects are references.
- aload pop pop pdfwriteobj
- } {
- pop
- } ifelse
- } forall
- % Walk the object graph.
- {
- ToWrite dup length dup 0 eq { pop pop exit } if
- 1 sub 2 copy get 3 1 roll undef aload pop pdfwriteobj
- } loop
- % Write the xref table and trailer.
- /xref OFile fileposition def
- 0 XRef length 1 add pdfwritexref
- trailer dup length 1 add dict copy
- dup /Size XRef length 1 add put pdfwritetrailer
- xref pdfwritestartxref
- end
- } def
- .setglobal
|