new attribute handling in text module completed
[PyX/mjg.git] / pyx / epsfile.py
blobfc6a60d8bd38ff01340de262490b7af20ce2faef
1 #!/usr/bin/env python
2 # -*- coding: ISO-8859-1 -*-
5 # Copyright (C) 2002, 2003 Jörg Lehmann <joergl@users.sourceforge.net>
6 # Copyright (C) 2002, 2003 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 import re
25 import base, bbox, canvas, prolog, unit, trafo
27 # PostScript-procedure definitions (cf. 5002.EPSF_Spec_v3.0.pdf)
28 # with important correction in EndEPSF:
29 # end operator is missing in the spec!
31 _BeginEPSF = prolog.definition("BeginEPSF", """{
32 /b4_Inc_state save def
33 /dict_count countdictstack def
34 /op_count count 1 sub def
35 userdict begin
36 /showpage { } def
37 0 setgray 0 setlinecap
38 1 setlinewidth 0 setlinejoin
39 10 setmiterlimit [ ] 0 setdash newpath
40 /languagelevel where
41 {pop languagelevel
42 1 ne
43 {false setstrokeadjust false setoverprint
44 } if
45 } if
46 } bind""")
48 _EndEPSF = prolog.definition("EndEPSF", """{
49 end
50 count op_count sub {pop} repeat
51 countdictstack dict_count sub {end} repeat
52 b4_Inc_state restore
53 } bind""")
55 def _readbbox(filename):
56 """returns bounding box of EPS file filename as 4-tuple (llx, lly, urx, ury)"""
58 try:
59 file = open(filename, "r")
60 except:
61 raise IOError, "cannot open EPS file '%s'" % filename
63 bbpattern = re.compile( r"""^%%BoundingBox:\s+([+-]?\d+)
64 \s+([+-]?\d+)
65 \s+([+-]?\d+)
66 \s+([+-]?\d+)\s*$""" , re.VERBOSE)
68 try:
69 readlinesfunc = file.xreadlines
70 except: # workaround for Python 2.0
71 readlinesfunc = file.readlines
72 for line in readlinesfunc():
74 if line=="%%EndComments\n":
75 # XXX: BoundingBox-Deklaration kann auch an Ende von Datei
76 # verschoben worden sein...
77 # ...but evaluation of such a bbox directive requires
78 # a parsing of the DSC!
79 raise IOError, \
80 "bounding box not found in header of EPS file '%s'" % \
81 filename
83 bbmatch = bbpattern.match(line)
84 if bbmatch is not None:
85 # conversion strings->int
86 (llx, lly, urx, ury) = map(int, bbmatch.groups())
87 return bbox._bbox(llx, lly, urx, ury)
88 else:
89 raise IOError, \
90 "bounding box not found in EPS file '%s'" % filename
93 class epsfile(base.PSCmd):
95 """class for epsfiles"""
97 def __init__(self,
98 x, y, filename,
99 width=None, height=None, scale=None,
100 align="bl",
101 clip=1,
102 showbbox = 0,
103 translatebbox = 1,
104 bbox = None):
105 """inserts epsfile
107 inserts EPS file named filename at position (x,y). If clip is
108 set, the result gets clipped to the bbox of the EPS file. If
109 translatebbox is not set, the EPS graphics is not translated to
110 the corresponding origin. With showbb set, the bbox is drawn.
111 If bbox is specified, it overrides the bounding box in the epsfile
112 itself.
116 self._x = unit.topt(x)
117 self._y = unit.topt(y)
118 self.filename = filename
119 self.mybbox = bbox or _readbbox(self.filename)
121 # determine scaling in x and y direction
122 self.scalex = self.scaley = scale
124 if width is not None or height is not None:
125 if scale is not None:
126 raise ValueError("cannot set both width and/or height and scale simultaneously")
127 if height is not None:
128 self.scaley = unit.topt(height)/(self.mybbox.ury-self.mybbox.lly)
129 if width is not None:
130 self.scalex = unit.topt(width)/(self.mybbox.urx-self.mybbox.llx)
132 if self.scalex is None:
133 self.scalex = self.scaley
134 if self.scaley is None:
135 self.scaley = self.scalex
137 # set the actual width and height of the eps file (after a
138 # possible scaling)
139 self._width = (self.mybbox.urx-self.mybbox.llx)
140 if self.scalex:
141 self._width *= self.scalex
143 self._height = (self.mybbox.ury-self.mybbox.lly)
144 if self.scaley:
145 self._height *= self.scaley
147 # take alignment into account
148 self.align = align
149 if self.align[0]=="b":
150 pass
151 elif self.align[0]=="c":
152 self._y -= self._height/2.0
153 elif self.align[0]=="t":
154 self._y -= self._height
155 else:
156 raise ValueError("vertical alignment can only be b (bottom), c (center), or t (top)")
158 if self.align[1]=="l":
159 pass
160 elif self.align[1]=="c":
161 self._x -= self._width/2.0
162 elif self.align[1]=="r":
163 self._x -= self._width
164 else:
165 raise ValueError("horizontal alignment can only be l (left), c (center), or r (right)")
167 self.clip = clip
168 self.translatebbox = translatebbox
169 self.showbbox = showbbox
171 self.trafo = trafo._translate(self._x, self._y)
173 if self.scalex is not None:
174 self.trafo = self.trafo * trafo._scale(self.scalex, self.scaley)
176 if translatebbox:
177 self.trafo = self.trafo * trafo._translate(-self.mybbox.llx, -self.mybbox.lly)
179 def bbox(self):
180 return self.mybbox.transformed(self.trafo)
182 def prolog(self):
183 return [_BeginEPSF, _EndEPSF]
185 def write(self, file):
186 try:
187 epsfile=open(self.filename,"r")
188 except:
189 raise IOError, "cannot open EPS file '%s'" % self.filename
191 file.write("BeginEPSF\n")
193 bbrect = self.mybbox.rect().transformed(self.trafo)
195 if self.showbbox:
196 canvas._newpath().write(file)
197 bbrect.write(file)
198 canvas._stroke().write(file)
200 if self.clip:
201 canvas._newpath().write(file)
202 bbrect.write(file)
203 canvas._clip().write(file)
205 self.trafo.write(file)
207 file.write("%%%%BeginDocument: %s\n" % self.filename)
208 file.write(epsfile.read())
209 file.write("%%EndDocument\n")
210 file.write("EndEPSF\n")