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
25 import base
, bbox
, 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
37 0 setgray 0 setlinecap
38 1 setlinewidth 0 setlinejoin
39 10 setmiterlimit [ ] 0 setdash newpath
43 {false setstrokeadjust false setoverprint
48 _EndEPSF
= prolog
.definition("EndEPSF", """{
50 count op_count sub {pop} repeat
51 countdictstack dict_count sub {end} repeat
55 def _readbbox(filename
):
56 """returns bounding box of EPS file filename"""
58 file = open(filename
, "r")
61 def readlinewithexception():
62 line
= file.readline()
64 raise IOError("unexpected end of file")
67 # check the %! header comment
68 if not readlinewithexception().startswith("%!"):
69 raise IOError("file doesn't start with a '%!' header comment")
72 # parse the header (use the first BoundingBox)
74 line
= readlinewithexception()
75 if line
.startswith("%%BoundingBox:") and not bboxatend
:
76 values
= line
.split(":", 1)[1].split()
77 if values
== ["(atend)"]:
81 raise IOError("invalid number of bounding box values")
82 return bbox
.bbox_pt(*map(int, values
))
83 elif (line
.rstrip() == "%%EndComments" or
84 (line
[0] != "%" and line
[1] not in string
.whitespace
)): # implicit end of comments section
87 raise IOError("no bounding box information found")
90 nesting
= 0 # allow for nested documents
92 line
= readlinewithexception()
93 if line
.startswith("%%BeginData:"):
94 values
= line
.split(":", 1)[1].split()
96 raise IOError("invalid number of arguments")
98 if values
[2] == "Lines":
99 for i
in xrange(int(values
[0])):
100 readlinewithexception()
101 elif values
[2] != "Bytes":
102 raise IOError("invalid bytesorlines-value")
104 file.read(int(values
[0]))
106 file.read(int(values
[0]))
107 line
= readlinewithexception()
108 # ignore tailing whitespace/newline for binary data
109 if (len(values
) < 3 or values
[2] != "Lines") and not len(line
.strip()):
110 line
= readlinewithexception()
111 if line
.rstrip() != "%%EndData":
112 raise IOError("missing EndData")
113 elif line
.startswith("%%BeginBinary:"):
114 file.read(int(line
.split(":", 1)[1]))
115 line
= readlinewithexception()
116 # ignore tailing whitespace/newline
117 if not len(line
.strip()):
118 line
= readlinewithexception()
119 if line
.rstrip() != "%%EndBinary":
120 raise IOError("missing EndBinary")
121 elif line
.startswith("%%BeginDocument:"):
123 elif line
.rstrip() == "%%EndDocument":
125 raise IOError("unmatched EndDocument")
127 elif not nesting
and line
.rstrip() == "%%Trailer":
131 # parse the trailer (use the last BoundingBox)
133 line
= file.readline()
134 if line
.startswith("%%BoundingBox:"):
135 values
= line
.split(":", 1)[1].split()
137 raise IOError("invalid number of bounding box values")
138 usebbox
= bbox
.bbox_pt(*map(int, values
))
142 raise IOError("missing bounding box information in document trailer")
146 class epsfile(base
.PSCmd
):
148 """class for epsfiles"""
152 width
=None, height
=None, scale
=None,
159 inserts EPS file named filename at position (x,y). If clip is
160 set, the result gets clipped to the bbox of the EPS file. If
161 translatebbox is not set, the EPS graphics is not translated to
162 the corresponding origin. If bbox is not None, it overrides
163 the bounding box in the epsfile itself.
167 self
.x_pt
= unit
.topt(x
)
168 self
.y_pt
= unit
.topt(y
)
169 self
.filename
= filename
170 self
.mybbox
= bbox
or _readbbox(self
.filename
)
172 # determine scaling in x and y direction
173 self
.scalex
= self
.scaley
= scale
175 if width
is not None or height
is not None:
176 if scale
is not None:
177 raise ValueError("cannot set both width and/or height and scale simultaneously")
178 if height
is not None:
179 self
.scaley
= unit
.topt(height
)/(self
.mybbox
.ury_pt
-self
.mybbox
.lly_pt
)
180 if width
is not None:
181 self
.scalex
= unit
.topt(width
)/(self
.mybbox
.urx_pt
-self
.mybbox
.llx_pt
)
183 if self
.scalex
is None:
184 self
.scalex
= self
.scaley
185 if self
.scaley
is None:
186 self
.scaley
= self
.scalex
188 # set the actual width and height of the eps file (after a
190 self
.width_pt
= self
.mybbox
.urx_pt
-self
.mybbox
.llx_pt
192 self
.width_pt
*= self
.scalex
194 self
.height_pt
= self
.mybbox
.ury_pt
-self
.mybbox
.lly_pt
196 self
.height_pt
*= self
.scaley
198 # take alignment into account
200 if self
.align
[0]=="b":
202 elif self
.align
[0]=="c":
203 self
.y_pt
-= self
.height_pt
/2.0
204 elif self
.align
[0]=="t":
205 self
.y_pt
-= self
.height_pt
207 raise ValueError("vertical alignment can only be b (bottom), c (center), or t (top)")
209 if self
.align
[1]=="l":
211 elif self
.align
[1]=="c":
212 self
.x_pt
-= self
.width_pt
/2.0
213 elif self
.align
[1]=="r":
214 self
.x_pt
-= self
.width_pt
216 raise ValueError("horizontal alignment can only be l (left), c (center), or r (right)")
219 self
.translatebbox
= translatebbox
221 self
.trafo
= trafo
.translate_pt(self
.x_pt
, self
.y_pt
)
223 if self
.scalex
is not None:
224 self
.trafo
= self
.trafo
* trafo
.scale_pt(self
.scalex
, self
.scaley
)
227 self
.trafo
= self
.trafo
* trafo
.translate_pt(-self
.mybbox
.llx_pt
, -self
.mybbox
.lly_pt
)
230 return self
.mybbox
.transformed(self
.trafo
)
233 return [_BeginEPSF
, _EndEPSF
]
235 def outputPS(self
, file):
237 epsfile
=open(self
.filename
,"r")
239 raise IOError, "cannot open EPS file '%s'" % self
.filename
241 file.write("BeginEPSF\n")
243 bbrect
= self
.mybbox
.rect().transformed(self
.trafo
)
246 file.write("newpath\n")
247 bbrect
.outputPS(file)
250 self
.trafo
.outputPS(file)
252 file.write("%%%%BeginDocument: %s\n" % self
.filename
)
253 file.write(epsfile
.read())
254 file.write("%%EndDocument\n")
255 file.write("EndEPSF\n")