GPL -> Latex license
[PyX/mjg.git] / pyx / epsfile.py
blob6dca13dbe365bfb8ccf06ef911659ad9fc748baa
1 #!/usr/bin/env python
4 # Copyright (C) 2002 Jörg Lehmann <joergl@users.sourceforge.net>
5 # Copyright (C) 2002 André Wobst <wobsta@users.sourceforge.net>
7 # This file is part of PyX (http://pyx.sourceforge.net/).
9 # PyX is free software; you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 2 of the License, or
12 # (at your option) any later version.
14 # PyX is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with PyX; if not, write to the Free Software
21 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 import re
24 import base, bbox, canvas, unit, trafo
26 # PostScript-procedure definitions (cf. 5002.EPSF_Spec_v3.0.pdf)
27 # with important correction in EndEPSF:
28 # end operator is missing in the spec!
30 _BeginEPSF = canvas.definition("BeginEPSF", """{
31 /b4_Inc_state save def
32 /dict_count countdictstack def
33 /op_count count 1 sub def
34 userdict begin
35 /showpage { } def
36 0 setgray 0 setlinecap
37 1 setlinewidth 0 setlinejoin
38 10 setmiterlimit [ ] 0 setdash newpath
39 /languagelevel where
40 {pop languagelevel
41 1 ne
42 {false setstrokeadjust false setoverprint
43 } if
44 } if
45 } bind""")
47 _EndEPSF = canvas.definition("EndEPSF", """{
48 end
49 count op_count sub {pop} repeat
50 countdictstack dict_count sub {end} repeat
51 b4_Inc_state restore
52 } bind""")
54 def _readbbox(filename):
55 """returns bounding box of EPS file filename as 4-tuple (llx, lly, urx, ury)"""
57 try:
58 file = open(filename, "r")
59 except:
60 raise IOError, "cannot open EPS file '%s'" % filename
62 bbpattern = re.compile( r"""^%%BoundingBox:\s+([+-]?\d+)
63 \s+([+-]?\d+)
64 \s+([+-]?\d+)
65 \s+([+-]?\d+)\s*$""" , re.VERBOSE)
67 for line in file.xreadlines():
69 if line=="%%EndComments\n":
70 # XXX: BoundingBox-Deklaration kann auch an Ende von Datei
71 # verschoben worden sein...
72 # ...but evaluation of such a bbox directive requires
73 # a parsing of the DSC!
74 raise IOError, \
75 "bounding box not found in header of EPS file '%s'" % \
76 filename
78 bbmatch = bbpattern.match(line)
79 if bbmatch is not None:
80 # conversion strings->int
81 (llx, lly, urx, ury) = map(int, bbmatch.groups())
82 return bbox._bbox(llx, lly, urx, ury)
83 else:
84 raise IOError, \
85 "bounding box not found in EPS file '%s'" % filename
88 class epsfile(base.PSCmd):
90 """class for epsfiles"""
92 def __init__(self,
93 x, y, filename,
94 width=None, height=None, scale=None,
95 align="bl",
96 clip=1,
97 showbbox = 0,
98 translatebbox = 1):
99 """inserts epsfile
101 inserts EPS file named filename at position (x,y). If clip is
102 set, the result gets clipped to the bbox of the EPS file. If
103 translatebbox is not set, the EPS graphics is not translated to
104 the corresponding origin. With showbb set, the bbox is drawn.
108 self._x = unit.topt(x)
109 self._y = unit.topt(y)
110 self.filename = filename
111 self.mybbox = _readbbox(self.filename)
113 # determine scaling in x and y direction
114 self.scalex = self.scaley = scale
116 if (width is not None or height is not None):
117 if scale is not None:
118 raise ValueError("cannot set both width and/or height and scale simultaneously")
119 if height is not None:
120 self.scalex = unit.topt(height)/(self.mybbox.urx-self.mybbox.llx)
121 if width is not None:
122 self.scaley = unit.topt(width)/(self.mybbox.ury-self.mybbox.lly)
124 if self.scalex is None:
125 self.scalex = self.scaley
127 if self.scaley is None:
128 self.scaley = self.scalex
130 # set the actual width and height of the eps file (after a
131 # possible scaling)
132 self._width = (self.mybbox.urx-self.mybbox.llx)
133 if self.scalex:
134 self._width *= self.scalex
136 self._height = (self.mybbox.ury-self.mybbox.lly)
137 if self.scaley:
138 self._height *= self.scaley
140 # take alignment into account
141 self.align = align
142 if self.align[0]=="b":
143 pass
144 elif self.align[0]=="c":
145 self._y -= self._height/2.0
146 elif self.align[0]=="t":
147 self._y -= self._height
148 else:
149 raise ValueError("vertical alignment can only be b (bottom), c (center), or t (top)")
151 if self.align[1]=="l":
152 pass
153 elif self.align[1]=="c":
154 self._x -= self._width/2.0
155 elif self.align[1]=="r":
156 self._x -= self._width
157 else:
158 raise ValueError("horizontal alignment can only be l (left), c (center), or r (right)")
160 self.clip = clip
161 self.translatebbox = translatebbox
162 self.showbbox = showbbox
164 self.trafo = trafo._translate(self._x, self._y)
166 if self.scalex is not None:
167 self.trafo = self.trafo * trafo._scale(self.scalex, self.scaley)
169 if translatebbox:
170 self.trafo = self.trafo * trafo._translate(-self.mybbox.llx, -self.mybbox.lly)
172 def bbox(self):
173 return self.mybbox.transformed(self.trafo)
175 def prolog(self):
176 return [_BeginEPSF, _EndEPSF]
178 def write(self, file):
179 try:
180 epsfile=open(self.filename,"r")
181 except:
182 raise IOError, "cannot open EPS file '%s'" % self.filename
184 file.write("BeginEPSF\n")
186 bbrect = self.mybbox.rect().transformed(self.trafo)
188 if self.showbbox:
189 canvas._newpath().write(file)
190 bbrect.write(file)
191 canvas._stroke().write(file)
193 if self.clip:
194 canvas._newpath().write(file)
195 bbrect.write(file)
196 canvas._clip().write(file)
198 self.trafo.write(file)
200 file.write("%%%%BeginDocument: %s\n" % self.filename)
201 file.write(epsfile.read())
202 file.write("%%EndDocument\n")
203 file.write("EndEPSF\n")