- adjustments to the new graph data+style handling
[PyX/mjg.git] / pyx / pdfwriter.py
blobc31a8ff8f6c68e16ad27232c14099c5f54ffe384
1 import sys
2 try:
3 import zlib
4 haszlib = 1
5 except:
6 haszlib = 0
8 import style
10 PDFcatalog = "Catalog"
11 PDFpages = "Pages"
12 PDFpage = "Page%i"
13 PDFmediabox = "MediaBox%i"
14 PDFresources = "Resources%i"
15 PDFcontents = "Contents%i"
16 PDFcontentslength = "ContentsLength%i"
18 class pdfwriter:
20 def __init__(self, filename, compress=1, compresslevel=6):
21 self.file = open(filename, "wb")
22 if compress and not haszlib:
23 compress = 0
24 sys.stderr.write("*** PyXWarning: compression disabled due to missing zlib module\n")
25 self.compress = compress
26 self.compresslevel = compresslevel
28 self.compressstream = None
29 self.refdict = {} # id -> ref-no
30 self.refs = [] # refno - 1 -> filepos
31 self.pages = 0
33 self.write("%%PDF-1.4\n%%%s%s%s%s\n" % (chr(195), chr(182), chr(195), chr(169)))
35 def write(self, str):
36 if self.compressstream is not None:
37 self.file.write(self.compressstream.compress(str))
38 else:
39 self.file.write(str)
41 def beginobj(self, object):
42 self.refs.append(self.file.tell())
43 ref = len(self.refs)
44 self.refdict[object] = ref
45 self.write("%i 0 obj\n" % ref)
47 def endobj(self):
48 self.write("endobj\n")
50 def beginstream(self):
51 self.write("stream\n")
52 self.beginstreampos = self.file.tell()
53 if self.compress:
54 if self.compressstream is not None:
55 raise RuntimeError("compression within compression")
56 self.compressstream = zlib.compressobj(self.compresslevel)
58 def endstream(self):
59 if self.compressstream is not None:
60 self.file.write(self.compressstream.flush())
61 self.compressstream = None
62 length = self.file.tell() - self.beginstreampos
63 self.write("endstream\n")
64 return length
66 def page(self, abbox, canvas, mergedprolog, ctrafo):
67 # media box
68 self.beginobj(PDFmediabox % self.pages)
69 abbox.outputPDF(self)
70 self.endobj()
72 # resources
73 self.beginobj(PDFresources % self.pages)
74 self.write("<<\n")
75 if len([pritem for pritem in mergedprolog if isinstance(pritem, prolog.fontdefinition)]):
76 self.write("/Font\n"
77 "<<\n")
78 for pritem in mergedprolog:
79 if isinstance(pritem, prolog.fontdefinition):
80 self.write("/%s %d 0 R\n" % (pritem.font.getpsname(),
81 self.refdict[pritem.font.getpsname()]))
82 self.write(">>\n")
83 self.write(">>\n")
84 self.endobj()
86 # contents
87 contentslengthref = len(self.refs) + 2
88 self.beginobj(PDFcontents % self.pages)
89 self.write("<<\n"
90 "/Length %i 0 R\n" % contentslengthref)
91 if self.compress:
92 self.write("/Filter /FlateDecode\n")
93 self.write(">>\n")
94 self.beginstream()
95 # apply a possible global transformation
96 if ctrafo: ctrafo.outputPDF(self)
97 style.linewidth.normal.outputPDF(self)
98 canvas.outputPDF(self)
99 contentslength = self.endstream()
100 self.endobj()
102 # contents length
103 self.beginobj(PDFcontentslength % self.pages)
104 self.write("%i\n" % contentslength)
105 self.endobj()
106 assert contentslengthref == self.refdict[PDFcontentslength % self.pages]
108 self.pages += 1
110 def close(self):
111 # page objects and pages object
112 # XXX: note that the page objects and the pages object refer to each other
113 pagesref = len(self.refs) + self.pages + 1
114 for page in range(self.pages):
115 self.beginobj(PDFpage % page)
116 self.write("<<\n"
117 "/Type /Page\n"
118 "/Parent %i 0 R\n"
119 "/MediaBox %i 0 R\n"
120 "/Resources %i 0 R\n"
121 "/Contents %i 0 R\n"
122 ">>\n" % (pagesref,
123 self.refdict[PDFmediabox % page],
124 self.refdict[PDFresources % page],
125 self.refdict[PDFcontents % page]))
126 self.endobj()
127 self.beginobj(PDFpages)
128 self.write("<<\n"
129 "/Type /Pages\n"
130 "/Kids [%s]\n"
131 "/Count %i\n"
132 ">>\n" % (" ".join(["%i 0 R" % self.refdict[PDFpage % page]
133 for page in range(self.pages)]),
134 self.pages))
135 self.endobj()
136 assert pagesref == self.refdict[PDFpages]
138 # catalog
139 self.beginobj(PDFcatalog)
140 self.write("<<\n"
141 "/Type /Catalog\n"
142 "/Pages %i 0 R\n"
143 ">>\n" % self.refdict[PDFpages])
144 self.endobj()
146 # xref
147 xrefpos = self.file.tell()
148 self.write("xref\n"
149 "0 %d\n"
150 "0000000000 65535 f \n" % (len(self.refs)+1))
151 for ref in self.refs:
152 self.file.write("%010i 00000 n \n" % ref)
154 # trailer
155 self.write("trailer\n"
156 "<<\n"
157 "/Size %i\n"
158 "/Root %i 0 R\n"
159 ">>\n"
160 "startxref\n"
161 "%i\n"
162 "%%%%EOF\n" % (len(self.refs)+1, self.refdict[PDFcatalog], xrefpos))
163 self.file.close()