umask
[PyX/mjg.git] / pyx / epsfile.py
blobae9f173a9f6cecb6a60864ddb0afbc9bca95c98c
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 for line in file.xreadlines():
70 if line=="%%EndComments\n":
71 # XXX: BoundingBox-Deklaration kann auch an Ende von Datei
72 # verschoben worden sein...
73 # ...but evaluation of such a bbox directive requires
74 # a parsing of the DSC!
75 raise IOError, \
76 "bounding box not found in header of EPS file '%s'" % \
77 filename
79 bbmatch = bbpattern.match(line)
80 if bbmatch is not None:
81 # conversion strings->int
82 (llx, lly, urx, ury) = map(int, bbmatch.groups())
83 return bbox._bbox(llx, lly, urx, ury)
84 else:
85 raise IOError, \
86 "bounding box not found in EPS file '%s'" % filename
89 class epsfile(base.PSCmd):
91 """class for epsfiles"""
93 def __init__(self,
94 x, y, filename,
95 width=None, height=None, scale=None,
96 align="bl",
97 clip=1,
98 showbbox = 0,
99 translatebbox = 1,
100 bbox = None):
101 """inserts epsfile
103 inserts EPS file named filename at position (x,y). If clip is
104 set, the result gets clipped to the bbox of the EPS file. If
105 translatebbox is not set, the EPS graphics is not translated to
106 the corresponding origin. With showbb set, the bbox is drawn.
107 If bbox is specified, it overrides the bounding box in the epsfile
108 itself.
112 self._x = unit.topt(x)
113 self._y = unit.topt(y)
114 self.filename = filename
115 self.mybbox = bbox or _readbbox(self.filename)
117 # determine scaling in x and y direction
118 self.scalex = self.scaley = scale
120 if width is not None or height is not None:
121 if scale is not None:
122 raise ValueError("cannot set both width and/or height and scale simultaneously")
123 if height is not None:
124 self.scaley = unit.topt(height)/(self.mybbox.ury-self.mybbox.lly)
125 if width is not None:
126 self.scalex = unit.topt(width)/(self.mybbox.urx-self.mybbox.llx)
128 if self.scalex is None:
129 self.scalex = self.scaley
130 if self.scaley is None:
131 self.scaley = self.scalex
133 # set the actual width and height of the eps file (after a
134 # possible scaling)
135 self._width = (self.mybbox.urx-self.mybbox.llx)
136 if self.scalex:
137 self._width *= self.scalex
139 self._height = (self.mybbox.ury-self.mybbox.lly)
140 if self.scaley:
141 self._height *= self.scaley
143 # take alignment into account
144 self.align = align
145 if self.align[0]=="b":
146 pass
147 elif self.align[0]=="c":
148 self._y -= self._height/2.0
149 elif self.align[0]=="t":
150 self._y -= self._height
151 else:
152 raise ValueError("vertical alignment can only be b (bottom), c (center), or t (top)")
154 if self.align[1]=="l":
155 pass
156 elif self.align[1]=="c":
157 self._x -= self._width/2.0
158 elif self.align[1]=="r":
159 self._x -= self._width
160 else:
161 raise ValueError("horizontal alignment can only be l (left), c (center), or r (right)")
163 self.clip = clip
164 self.translatebbox = translatebbox
165 self.showbbox = showbbox
167 self.trafo = trafo._translate(self._x, self._y)
169 if self.scalex is not None:
170 self.trafo = self.trafo * trafo._scale(self.scalex, self.scaley)
172 if translatebbox:
173 self.trafo = self.trafo * trafo._translate(-self.mybbox.llx, -self.mybbox.lly)
175 def bbox(self):
176 return self.mybbox.transformed(self.trafo)
178 def prolog(self):
179 return [_BeginEPSF, _EndEPSF]
181 def write(self, file):
182 try:
183 epsfile=open(self.filename,"r")
184 except:
185 raise IOError, "cannot open EPS file '%s'" % self.filename
187 file.write("BeginEPSF\n")
189 bbrect = self.mybbox.rect().transformed(self.trafo)
191 if self.showbbox:
192 canvas._newpath().write(file)
193 bbrect.write(file)
194 canvas._stroke().write(file)
196 if self.clip:
197 canvas._newpath().write(file)
198 bbrect.write(file)
199 canvas._clip().write(file)
201 self.trafo.write(file)
203 file.write("%%%%BeginDocument: %s\n" % self.filename)
204 file.write(epsfile.read())
205 file.write("%%EndDocument\n")
206 file.write("EndEPSF\n")