2 # -*- coding: ISO-8859-1 -*-
5 # Copyright (C) 2002-2004 Jörg Lehmann <joergl@users.sourceforge.net>
6 # Copyright (C) 2002-2004 André Wobst <wobsta@users.sourceforge.net>
8 # This file is part of PyX (http://pyx.sourceforge.net/).
10 # PyX is free software; you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation; either version 2 of the License, or
13 # (at your option) any later version.
15 # PyX is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
20 # You should have received a copy of the GNU General Public License
21 # along with PyX; if not, write to the Free Software
22 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 # XXX what are the correct base classes of clip and pattern
26 """The canvas module provides a PostScript canvas class and related classes
28 A canvas holds a collection of all elements that should be displayed together
29 with their attributes.
32 import sys
, cStringIO
, time
33 import attr
, base
, bbox
, deco
, unit
, prolog
, style
, trafo
, version
35 # temporary for pdf fonts:
37 from t1strip
import fullfont
43 # fallback implementation for Python 2.2. and below
45 return zip(xrange(len(list)), list)
47 # known paperformats as tuple (width, height)
49 _paperformats
= { "A4" : (210 * unit
.t_mm
, 297 * unit
.t_mm
),
50 "A3" : (297 * unit
.t_mm
, 420 * unit
.t_mm
),
51 "A2" : (420 * unit
.t_mm
, 594 * unit
.t_mm
),
52 "A1" : (594 * unit
.t_mm
, 840 * unit
.t_mm
),
53 "A0" : (840 * unit
.t_mm
, 1188 * unit
.t_mm
),
54 "A0b" : (910 * unit
.t_mm
, 1370 * unit
.t_mm
),
55 "Letter" : (8.5 * unit
.t_inch
, 11 * unit
.t_inch
),
56 "Legal" : (8.5 * unit
.t_inch
, 14 * unit
.t_inch
)}
62 class clip(base
.PSCmd
):
64 """class for use in canvas constructor which clips to a path"""
66 def __init__(self
, path
):
67 """construct a clip instance for a given path"""
71 # as a PSCmd a clipping path has NO influence on the bbox...
75 # ... but for clipping, we nevertheless need the bbox
76 return self
.path
.bbox()
78 def outputPS(self
, file):
79 file.write("newpath\n")
80 self
.path
.outputPS(file)
83 def outputPDF(self
, file):
84 self
.path
.outputPDF(file)
88 # general canvas class
91 class _canvas(base
.PSCmd
):
93 """a canvas is a collection of PSCmds together with PSAttrs"""
95 def __init__(self
, attrs
=[], texrunner
=None):
99 The canvas can be modfied by supplying args, which have
100 to be instances of one of the following classes:
101 - trafo.trafo (leading to a global transformation of the canvas)
102 - canvas.clip (clips the canvas)
103 - base.PathStyle (sets some global attributes of the canvas)
105 Note that, while the first two properties are fixed for the
106 whole canvas, the last one can be changed via canvas.set().
108 The texrunner instance used for the text method can be specified
109 using the texrunner argument. It defaults to text.defaulttexrunner
114 self
.trafo
= trafo
.trafo()
116 if texrunner
is not None:
117 self
.texrunner
= texrunner
119 # prevent cyclic imports
121 self
.texrunner
= text
.defaulttexrunner
124 if isinstance(attr
, trafo
.trafo_pt
):
125 self
.trafo
= self
.trafo
*attr
126 self
.PSOps
.append(attr
)
127 elif isinstance(attr
, clip
):
128 if self
.clipbbox
is None:
129 self
.clipbbox
= attr
.clipbbox().transformed(self
.trafo
)
131 self
.clippbox
*= attr
.clipbbox().transformed(self
.trafo
)
132 self
.PSOps
.append(attr
)
137 """returns bounding box of canvas"""
139 for cmd
in self
.PSOps
:
140 if isinstance(cmd
, base
.PSCmd
):
144 elif abbox
is not None:
147 # transform according to our global transformation and
148 # intersect with clipping bounding box (which have already been
149 # transformed in canvas.__init__())
150 if obbox
is not None and self
.clipbbox
is not None:
151 return obbox
.transformed(self
.trafo
)*self
.clipbbox
152 elif obbox
is not None:
153 return obbox
.transformed(self
.trafo
)
159 for cmd
in self
.PSOps
:
160 result
.extend(cmd
.prolog())
163 def outputPS(self
, file):
165 file.write("gsave\n")
166 for cmd
in self
.PSOps
:
168 file.write("grestore\n")
170 def outputPDF(self
, file):
172 file.write("q\n") # gsave
173 for cmd
in self
.PSOps
:
175 file.write("Q\n") # grestore
177 def insert(self
, PSOp
, attrs
=[]):
178 """insert PSOp in the canvas.
180 If attrss are given, a canvas containing the PSOp is inserted applying attrs.
191 self
.PSOps
.append(sc
)
193 self
.PSOps
.append(PSOp
)
197 def set(self
, attrs
):
198 """sets styles args globally for the rest of the canvas
201 attr
.checkattrs(attrs
, [style
.strokestyle
, style
.fillstyle
])
205 def draw(self
, path
, attrs
):
206 """draw path on canvas using the style given by args
208 The argument attrs consists of PathStyles, which modify
209 the appearance of the path, PathDecos, which add some new
210 visual elements to the path, or trafos, which are applied
211 before drawing the path.
215 attrs
= attr
.mergeattrs(attrs
)
216 attr
.checkattrs(attrs
, [deco
.deco
, style
.fillstyle
, style
.strokestyle
, trafo
.trafo_pt
])
218 for t
in attr
.getattrs(attrs
, [trafo
.trafo_pt
]):
219 path
= path
.transformed(t
)
221 dp
= deco
.decoratedpath(path
)
224 dp
.styles
= attr
.getattrs(attrs
, [style
.fillstyle
, style
.strokestyle
])
226 # add path decorations and modify path accordingly
227 for adeco
in attr
.getattrs(attrs
, [deco
.deco
]):
228 dp
= adeco
.decorate(dp
)
232 def stroke(self
, path
, attrs
=[]):
233 """stroke path on canvas using the style given by args
235 The argument attrs consists of PathStyles, which modify
236 the appearance of the path, PathDecos, which add some new
237 visual elements to the path, or trafos, which are applied
238 before drawing the path.
242 self
.draw(path
, [deco
.stroked
]+list(attrs
))
244 def fill(self
, path
, attrs
=[]):
245 """fill path on canvas using the style given by args
247 The argument attrs consists of PathStyles, which modify
248 the appearance of the path, PathDecos, which add some new
249 visual elements to the path, or trafos, which are applied
250 before drawing the path.
254 self
.draw(path
, [deco
.filled
]+list(attrs
))
256 def settexrunner(self
, texrunner
):
257 """sets the texrunner to be used to within the text and text_pt methods"""
259 self
.texrunner
= texrunner
261 def text(self
, x
, y
, atext
, *args
, **kwargs
):
262 """insert a text into the canvas
264 inserts a textbox created by self.texrunner.text into the canvas
266 returns the inserted textbox"""
268 return self
.insert(self
.texrunner
.text(x
, y
, atext
, *args
, **kwargs
))
271 def text_pt(self
, x
, y
, atext
, *args
):
272 """insert a text into the canvas
274 inserts a textbox created by self.texrunner.text_pt into the canvas
276 returns the inserted textbox"""
278 return self
.insert(self
.texrunner
.text_pt(x
, y
, atext
, *args
))
281 # canvas for patterns
284 class pattern(_canvas
, attr
.exclusiveattr
, style
.fillstyle
):
286 def __init__(self
, painttype
=1, tilingtype
=1, xstep
=None, ystep
=None, bbox
=None, trafo
=None):
287 attr
.exclusiveattr
.__init
__(self
, pattern
)
288 _canvas
.__init
__(self
)
289 attr
.exclusiveattr
.__init
__(self
, pattern
)
290 self
.id = "pattern%d" % id(self
)
291 if painttype
not in (1,2):
292 raise ValueError("painttype must be 1 or 2")
293 self
.painttype
= painttype
294 if tilingtype
not in (1,2,3):
295 raise ValueError("tilingtype must be 1, 2 or 3")
296 self
.tilingtype
= tilingtype
299 self
.patternbbox
= bbox
300 self
.patterntrafo
= trafo
305 def outputPS(self
, file):
306 file.write("%s setpattern\n" % self
.id)
309 realpatternbbox
= _canvas
.bbox(self
)
310 if self
.xstep
is None:
311 xstep
= unit
.topt(realpatternbbox
.width())
313 xstep
= unit
.topt(self
.xstep
)
314 if self
.ystep
is None:
315 ystep
= unit
.topt(realpatternbbox
.height())
317 ystep
= unit
.topt(self
.ystep
)
319 raise ValueError("xstep in pattern cannot be zero")
321 raise ValueError("ystep in pattern cannot be zero")
322 patternbbox
= self
.patternbbox
or realpatternbbox
.enlarged(5*unit
.pt
)
324 patternprefix
= "\n".join(("<<",
326 "/PaintType %d" % self
.painttype
,
327 "/TilingType %d" % self
.tilingtype
,
328 "/BBox[%s]" % str(patternbbox
),
331 "/PaintProc {\nbegin\n"))
332 stringfile
= cStringIO
.StringIO()
333 _canvas
.outputPS(self
, stringfile
)
334 patternproc
= stringfile
.getvalue()
336 patterntrafostring
= self
.patterntrafo
is None and "matrix" or str(self
.patterntrafo
)
337 patternsuffix
= "end\n} bind\n>>\n%s\nmakepattern" % patterntrafostring
339 pr
= _canvas
.prolog(self
)
340 pr
.append(prolog
.definition(self
.id, "".join((patternprefix
, patternproc
, patternsuffix
))))
343 pattern
.clear
= attr
.clearclass(pattern
)
347 def calctrafo(abbox
, paperformat
, margin
, rotated
, fittosize
):
348 """ calculate a trafo which rotates and fits a canvas with
349 bounding box abbox on the given paperformat with a margin on all
351 if not isinstance(margin
, unit
.length
):
352 margin
= unit
.length(margin
)
353 atrafo
= None # global transformation of canvas
356 atrafo
= trafo
.rotate(90, *abbox
.center())
359 # center (optionally rotated) output on page
361 paperwidth
, paperheight
= _paperformats
[paperformat
.capitalize()]
363 raise KeyError, "unknown paperformat '%s'" % paperformat
365 paperwidth
-= 2*margin
366 paperheight
-= 2*margin
368 if not atrafo
: atrafo
= trafo
.trafo()
370 atrafo
= atrafo
.translated(margin
+ 0.5*(paperwidth
- abbox
.width()) - abbox
.left(),
371 margin
+ 0.5*(paperheight
- abbox
.height()) - abbox
.bottom())
374 # scale output to pagesize - margins
375 if 2*margin
> min(paperwidth
, paperheight
):
376 raise RuntimeError("Margins too broad for selected paperformat. Aborting.")
379 sfactor
= min(unit
.topt(paperheight
)/unit
.topt(abbox
.width()),
380 unit
.topt(paperwidth
)/unit
.topt(abbox
.height()))
382 sfactor
= min(unit
.topt(paperwidth
)/unit
.topt(abbox
.width()),
383 unit
.topt(paperheight
)/unit
.topt(abbox
.height()))
385 atrafo
= atrafo
.scaled(sfactor
, sfactor
, margin
+ 0.5*paperwidth
, margin
+ 0.5*paperheight
)
387 raise ValueError("must specify paper size for fittosize")
392 # The main canvas class
395 class canvas(_canvas
):
397 """a canvas is a collection of PSCmds together with PSAttrs"""
399 def writeEPSfile(self
, filename
, paperformat
=None, rotated
=0, fittosize
=0, margin
=1 * unit
.t_cm
,
400 bbox
=None, bboxenlarge
=1 * unit
.t_pt
):
401 """write canvas to EPS file
403 If paperformat is set to a known paperformat, the output will be centered on
406 If rotated is set, the output will first be rotated by 90 degrees.
408 If fittosize is set, then the output is scaled to the size of the
409 page (minus margin). In that case, the paperformat the specification
410 of the paperformat is obligatory.
412 The bbox parameter overrides the automatic bounding box determination.
413 bboxenlarge may be used to enlarge the bbox of the canvas (or the
414 manually specified bbox).
417 if filename
[-4:]!=".eps":
418 filename
= filename
+ ".eps"
421 file = open(filename
, "w")
423 raise IOError("cannot open output file")
425 abbox
= bbox
is not None and bbox
or self
.bbox()
426 abbox
.enlarge(bboxenlarge
)
427 ctrafo
= calctrafo(abbox
, paperformat
, margin
, rotated
, fittosize
)
429 # if there has been a global transformation, adjust the bounding box
431 if ctrafo
: abbox
.transform(ctrafo
)
433 file.write("%!PS-Adobe-3.0 EPSF 3.0\n")
435 file.write("%%%%Creator: PyX %s\n" % version
.version
)
436 file.write("%%%%Title: %s\n" % filename
)
437 file.write("%%%%CreationDate: %s\n" %
438 time
.asctime(time
.localtime(time
.time())))
439 file.write("%%EndComments\n")
441 file.write("%%BeginProlog\n")
445 for pritem
in self
.prolog():
446 for mpritem
in mergedprolog
:
447 if mpritem
.merge(pritem
) is None: break
449 mergedprolog
.append(pritem
)
451 for pritem
in mergedprolog
:
452 pritem
.outputPS(file)
454 file.write("%%EndProlog\n")
456 # apply a possible global transformation
457 if ctrafo
: ctrafo
.outputPS(file)
459 file.write("%f setlinewidth\n" % unit
.topt(style
.linewidth
.normal
))
461 # here comes the actual content
464 file.write("showpage\n")
465 file.write("%%Trailer\n")
466 file.write("%%EOF\n")
468 def writePDFfile(self
, filename
, paperformat
=None, rotated
=0, fittosize
=0, margin
=1 * unit
.t_cm
,
469 bbox
=None, bboxenlarge
=1 * unit
.t_pt
):
470 sys
.stderr
.write("*** PyX Warning: writePDFfile is experimental and supports only a subset of PyX's features\n")
472 if filename
[-4:]!=".pdf":
473 filename
= filename
+ ".pdf"
476 file = open(filename
, "wb")
478 raise IOError("cannot open output file")
480 abbox
= bbox
is not None and bbox
or self
.bbox()
481 abbox
.enlarge(bboxenlarge
)
483 ctrafo
= calctrafo(abbox
, paperformat
, margin
, rotated
, fittosize
)
485 # if there has been a global transformation, adjust the bounding box
487 if ctrafo
: abbox
.transform(ctrafo
)
491 for pritem
in self
.prolog():
492 for mpritem
in mergedprolog
:
493 if mpritem
.merge(pritem
) is None: break
495 mergedprolog
.append(pritem
)
497 file.write("%%PDF-1.4\n%%%s%s%s%s\n" % (chr(195), chr(182), chr(195), chr(169)))
498 reflist
= [file.tell()]
499 file.write("1 0 obj\n"
505 reflist
.append(file.tell())
506 file.write("2 0 obj\n"
513 reflist
.append(file.tell())
514 file.write("3 0 obj\n"
518 abbox
.outputPDF(file)
519 file.write("/Contents 4 0 R\n"
524 if len([pritem
for pritem
in mergedprolog
if isinstance(pritem
, prolog
.fontdefinition
)]):
527 for pritem
in mergedprolog
:
528 if isinstance(pritem
, prolog
.fontdefinition
):
530 file.write("/%s %d 0 R\n" % (pritem
.font
.getpsname(), fontnr
+fontstartref
))
531 fontnr
+= 3 # further objects due to a font
537 reflist
.append(file.tell())
538 file.write("4 0 obj\n"
539 "<< /Length 5 0 R >>\n"
541 streamstartpos
= file.tell()
543 # apply a possible global transformation
544 if ctrafo
: ctrafo
.outputPDF(file)
545 style
.linewidth
.normal
.outputPDF(file)
548 streamendpos
= file.tell()
549 file.write("endstream\n"
551 reflist
.append(file.tell())
552 file.write("5 0 obj\n"
554 "endobj\n" % (streamendpos
- streamstartpos
))
557 for pritem
in mergedprolog
:
558 if isinstance(pritem
, prolog
.fontdefinition
):
560 reflist
.append(file.tell())
561 file.write("%d 0 obj\n"
570 "/FontDescriptor %d 0 R\n"
571 "/Encoding /StandardEncoding\n" # FIXME
573 "endobj\n" % (fontnr
+fontstartref
, pritem
.font
.getpsname(), pritem
.font
.getbasepsname(),
574 fontnr
+fontstartref
+1, fontnr
+fontstartref
+2))
576 reflist
.append(file.tell())
577 file.write("%d 0 obj\n"
578 "[\n" % (fontnr
+fontstartref
))
581 width
= pritem
.font
.getwidth_pt(i
)*1000/pritem
.font
.getsize_pt()
584 file.write("%f\n" % width
)
589 reflist
.append(file.tell())
590 file.write("%d 0 obj\n"
592 "/Type /FontDescriptor\n"
595 "/FontBBox [-10 -10 1000 1000]\n" # FIXME
596 "/ItalicAngle 0\n" # FIXME
597 "/Ascent 20\n" # FIXME
598 "/Descent -5\n" # FIXME
599 "/CapHeight 15\n" # FIXME
601 "/FontFile %d 0 R\n" # FIXME
602 # "/CharSet \n" # fill in when stripping
604 "endobj\n" % (fontnr
+fontstartref
, pritem
.font
.getbasepsname(),
605 fontnr
+fontstartref
+1))
608 reflist
.append(file.tell())
610 fontdata
= open(pykpathsea
.find_file(pritem
.filename
, pykpathsea
.kpse_type1_format
)).read()
611 if fontdata
[0:2] != fullfont
._PFB
_ASCII
:
612 raise RuntimeError("PFB_ASCII mark expected")
613 length1
= fullfont
.pfblength(fontdata
[2:6])
614 if fontdata
[6+length1
:8+length1
] != fullfont
._PFB
_BIN
:
615 raise RuntimeError("PFB_BIN mark expected")
616 length2
= fullfont
.pfblength(fontdata
[8+length1
:12+length1
])
617 if fontdata
[12+length1
+length2
:14+length1
+length2
] != fullfont
._PFB
_ASCII
:
618 raise RuntimeError("PFB_ASCII mark expected")
619 length3
= fullfont
.pfblength(fontdata
[14+length1
+length2
:18+length1
+length2
])
620 if fontdata
[18+length1
+length2
+length3
:20+length1
+length2
+length3
] != fullfont
._PFB
_DONE
:
621 raise RuntimeError("PFB_DONE mark expected")
622 if len(fontdata
) != 20 + length1
+ length2
+ length3
:
623 raise RuntimeError("end of pfb file expected")
625 # we might be allowed to skip the third part ...
626 if fontdata
[18+length1
+length2
:18+length1
+length2
+length3
].replace("\n", "").replace("\r", "").replace("\t", "").replace(" ", "") == "0"*512 + "cleartomark":
629 uncompresseddata
= fontdata
[6:6+length1
] + fontdata
[12+length1
:12+length1
+length2
] + fontdata
[18+length1
+length2
:18+length1
+length2
+length3
]
630 compresseddata
= zlib
.compress(uncompresseddata
)
632 file.write("%d 0 obj\n"
638 "/Filter /FlateDecode\n"
640 "stream\n" % (fontnr
+fontstartref
, len(compresseddata
),
644 #file.write(fontdata[6:6+length1])
645 #file.write(fontdata[12+length1:12+length1+length2])
646 #file.write(fontdata[18+length1+length2:18+length1+length2+length3])
647 file.write(compresseddata
)
648 file.write("endstream\n"
653 xrefpos
= file.tell()
655 "0 %d\n" % (len(reflist
)+1))
656 file.write("0000000000 65535 f \n")
658 file.write("%010i 00000 n \n" % ref
)
659 file.write("trailer\n"
666 "%%%%EOF\n" % xrefpos
)
668 def writetofile(self
, filename
, *args
, **kwargs
):
669 if filename
[-4:] == ".eps":
670 self
.writeEPSfile(filename
, *args
, **kwargs
)
671 elif filename
[-4:] == ".pdf":
672 self
.writePDFfile(filename
, *args
, **kwargs
)
674 sys
.stderr
.write("*** PyX Warning: deprecated usage of writetofile -- writetofile needs a filename extension or use an explicit call to writeEPSfile or the like\n")
675 self
.writeEPSfile(filename
, *args
, **kwargs
)
679 def __init__(self
, attrs
=[], texrunner
=None, pagename
=None, paperformat
="a4", rotated
=0, fittosize
=0,
680 margin
=1 * unit
.t_cm
, bboxenlarge
=1 * unit
.t_pt
):
681 canvas
.__init
__(self
, attrs
, texrunner
)
682 self
.pagename
= pagename
683 self
.paperformat
= paperformat
.capitalize()
684 self
.rotated
= rotated
685 self
.fittosize
= fittosize
687 self
.bboxenlarge
= bboxenlarge
690 # the bounding box of a page is fixed by its format and an optional rotation
691 pbbox
= bbox
.bbox(0, 0, *_paperformats
[self
.paperformat
])
692 pbbox
.enlarge(self
.bboxenlarge
)
694 pbbox
.transform(trafo
.rotate(90, *pbbox
.center()))
697 def outputPS(self
, file):
698 file.write("%%%%PageMedia: %s\n" % self
.paperformat
)
699 file.write("%%%%PageOrientation: %s\n" % (self
.rotated
and "Landscape" or "Portrait"))
700 # file.write("%%%%PageBoundingBox: %d %d %d %d\n" % (math.floor(pbbox.llx_pt), math.floor(pbbox.lly_pt),
701 # math.ceil(pbbox.urx_pt), math.ceil(pbbox.ury_pt)))
704 file.write("%%BeginPageSetup\n")
705 file.write("/pgsave save def\n")
706 # for scaling, we need the real bounding box of the page contents
707 pbbox
= canvas
.bbox(self
)
708 pbbox
.enlarge(self
.bboxenlarge
)
709 ptrafo
= calctrafo(pbbox
, self
.paperformat
, self
.margin
, self
.rotated
, self
.fittosize
)
711 ptrafo
.outputPS(file)
712 file.write("%f setlinewidth\n" % unit
.topt(style
.linewidth
.normal
))
713 file.write("%%EndPageSetup\n")
715 # here comes the actual content
716 canvas
.outputPS(self
, file)
717 file.write("pgsave restore\n")
718 file.write("showpage\n")
719 # file.write("%%PageTrailer\n")
724 """holds a collection of page instances which are output as pages of a document"""
726 def __init__(self
, pages
=[]):
729 def append(self
, page
):
730 self
.pages
.append(page
)
732 def writePSfile(self
, filename
):
733 """write pages to PS file """
735 if filename
[-3:]!=".ps":
736 filename
= filename
+ ".ps"
739 file = open(filename
, "w")
741 raise IOError("cannot open output file")
744 for apage
in self
.pages
:
752 file.write("%!PS-Adobe-3.0\n")
753 docbbox
.outputPS(file)
754 file.write("%%%%Creator: PyX %s\n" % version
.version
)
755 file.write("%%%%Title: %s\n" % filename
)
756 file.write("%%%%CreationDate: %s\n" %
757 time
.asctime(time
.localtime(time
.time())))
758 # required paper formats
760 for apage
in self
.pages
:
761 if isinstance(apage
, page
):
762 paperformats
[apage
.paperformat
] = _paperformats
[apage
.paperformat
]
764 for paperformat
, size
in paperformats
.items():
766 file.write("%%DocumentMedia: ")
770 file.write("%s %d %d 75 white ()\n" % (paperformat
, unit
.topt(size
[0]), unit
.topt(size
[1])))
772 file.write("%%%%Pages: %d\n" % len(self
.pages
))
773 file.write("%%PageOrder: Ascend\n")
774 file.write("%%EndComments\n")
776 # document default section
777 #file.write("%%BeginDefaults\n")
779 # file.write("%%%%PageMedia: %s\n" % paperformat)
780 #file.write("%%%%PageOrientation: %s\n" % (rotated and "Landscape" or "Portrait"))
781 #file.write("%%EndDefaults\n")
783 # document prolog section
784 file.write("%%BeginProlog\n")
786 for apage
in self
.pages
:
787 for pritem
in apage
.prolog():
788 for mpritem
in mergedprolog
:
789 if mpritem
.merge(pritem
) is None: break
791 mergedprolog
.append(pritem
)
792 for pritem
in mergedprolog
:
793 pritem
.outputPS(file)
794 file.write("%%EndProlog\n")
796 # document setup section
797 #file.write("%%BeginSetup\n")
798 #file.write("%%EndSetup\n")
801 for nr
, apage
in enumerate(self
.pages
):
802 file.write("%%%%Page: %s %d\n" % (apage
.pagename
is None and str(nr
) or apage
.pagename
, nr
+1))
805 file.write("%%Trailer\n")
806 file.write("%%EOF\n")