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 as 4-tuple (llx_pt, lly_pt, urx_pt, ury_pt)"""
59 file = open(filename
, "r")
61 raise IOError, "cannot open EPS file '%s'" % filename
63 bbpattern
= re
.compile( r
"""^%%BoundingBox:\s+([+-]?\d+)
66 \s+([+-]?\d+)\s*$""" , re
.VERBOSE
)
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!
80 "bounding box not found in header of EPS file '%s'" % \
83 bbmatch
= bbpattern
.match(line
)
84 if bbmatch
is not None:
85 # conversion strings->int
86 (llx_pt
, lly_pt
, urx_pt
, ury_pt
) = map(int, bbmatch
.groups())
87 return bbox
.bbox_pt(llx_pt
, lly_pt
, urx_pt
, ury_pt
)
90 "bounding box not found in EPS file '%s'" % filename
93 class epsfile(base
.PSCmd
):
95 """class for epsfiles"""
99 width
=None, height
=None, scale
=None,
106 inserts EPS file named filename at position (x,y). If clip is
107 set, the result gets clipped to the bbox of the EPS file. If
108 translatebbox is not set, the EPS graphics is not translated to
109 the corresponding origin. If bbox is not None, it overrides
110 the bounding box in the epsfile itself.
114 self
._x
= unit
.topt(x
)
115 self
._y
= unit
.topt(y
)
116 self
.filename
= filename
117 self
.mybbox
= bbox
or _readbbox(self
.filename
)
119 # determine scaling in x and y direction
120 self
.scalex
= self
.scaley
= scale
122 if width
is not None or height
is not None:
123 if scale
is not None:
124 raise ValueError("cannot set both width and/or height and scale simultaneously")
125 if height
is not None:
126 self
.scaley
= unit
.topt(height
)/(self
.mybbox
.ury_pt
-self
.mybbox
.lly_pt
)
127 if width
is not None:
128 self
.scalex
= unit
.topt(width
)/(self
.mybbox
.urx_pt
-self
.mybbox
.llx_pt
)
130 if self
.scalex
is None:
131 self
.scalex
= self
.scaley
132 if self
.scaley
is None:
133 self
.scaley
= self
.scalex
135 # set the actual width and height of the eps file (after a
137 self
._width
= self
.mybbox
.urx_pt
-self
.mybbox
.llx_pt
139 self
._width
*= self
.scalex
141 self
._height
= self
.mybbox
.ury_pt
-self
.mybbox
.lly_pt
143 self
._height
*= self
.scaley
145 # take alignment into account
147 if self
.align
[0]=="b":
149 elif self
.align
[0]=="c":
150 self
._y
-= self
._height
/2.0
151 elif self
.align
[0]=="t":
152 self
._y
-= self
._height
154 raise ValueError("vertical alignment can only be b (bottom), c (center), or t (top)")
156 if self
.align
[1]=="l":
158 elif self
.align
[1]=="c":
159 self
._x
-= self
._width
/2.0
160 elif self
.align
[1]=="r":
161 self
._x
-= self
._width
163 raise ValueError("horizontal alignment can only be l (left), c (center), or r (right)")
166 self
.translatebbox
= translatebbox
168 self
.trafo
= trafo
.translate_pt(self
._x
, self
._y
)
170 if self
.scalex
is not None:
171 self
.trafo
= self
.trafo
* trafo
.scale_pt(self
.scalex
, self
.scaley
)
174 self
.trafo
= self
.trafo
* trafo
.translate_pt(-self
.mybbox
.llx_pt
, -self
.mybbox
.lly_pt
)
177 return self
.mybbox
.transformed(self
.trafo
)
180 return [_BeginEPSF
, _EndEPSF
]
182 def outputPS(self
, file):
184 epsfile
=open(self
.filename
,"r")
186 raise IOError, "cannot open EPS file '%s'" % self
.filename
188 file.write("BeginEPSF\n")
190 bbrect
= self
.mybbox
.rect().transformed(self
.trafo
)
193 file.write("newpath\n")
194 bbrect
.outputPS(file)
197 self
.trafo
.outputPS(file)
199 file.write("%%%%BeginDocument: %s\n" % self
.filename
)
200 file.write(epsfile
.read())
201 file.write("%%EndDocument\n")
202 file.write("EndEPSF\n")