2 # -*- coding: ISO-8859-1 -*-
5 # Copyright (C) 2005 Jörg Lehmann <joergl@users.sourceforge.net>
6 # Copyright (C) 2005 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 resource
, style
, version
26 import pykpathsea
, t1strip
35 def add(self
, resource
):
36 resources
= self
.types
.setdefault(resource
.type, {})
37 if resources
.has_key(resource
.id):
38 resources
[resource
.id].merge(resource
)
40 self
.resources
.append(resource
)
41 resources
[resource
.id] = resource
43 def outputPS(self
, file):
44 """ write all PostScript code of the prolog resources """
45 for resource
in self
.resources
:
46 resource
.outputPS(file)
54 """ a PostScript resource """
56 def __init__(self
, type, id):
57 # every PSresource has to have a type and a unique id
61 def merge(self
, other
):
64 def register(self
, registry
):
65 raise NotImplementedError("register not implemented for %s" % repr(self
))
67 def outputPS(self
, file):
68 raise NotImplementedError("outputPS not implemented for %s" % repr(self
))
71 # Different variants of prolog items
74 class PSdefinition(PSresource
):
76 """ PostScript function definition included in the prolog """
78 def __init__(self
, id, body
):
79 # every PSresource has to have a unique id
80 self
.type = "definition"
84 def register(self
, registry
):
85 registry
.addresource(registry
.definitions
, self
)
87 def outputPS(self
, file):
88 file.write("%%%%BeginRessource: %s\n" % self
.id)
89 file.write("%(body)s /%(id)s exch def\n" % self
.__dict
__)
90 file.write("%%EndRessource\n")
93 class PSfontfile(PSresource
):
95 """ PostScript font definition included in the prolog """
97 def __init__(self
, fontname
, filename
, encfilename
, usedchars
):
98 """ include type 1 font defined by the following parameters
100 - fontname: PostScript FontName of font
101 - filename: name (without path) of file containing the font definition
102 - encfilename: name (without path) of file containing used encoding of font
103 or None (if no encoding file used)
104 - usechars: list with 256 elements containing used charcodes of font
108 # Note that here we only need the encoding for selecting the used glyphs!
112 self
.type = "fontfile"
113 self
.id = self
.fontname
= fontname
114 self
.filename
= filename
115 self
.encfilename
= encfilename
116 self
.usedchars
= usedchars
118 def merge(self
, other
):
119 if self
.encfilename
!= other
.encfilename
:
120 self
.usedchars
= None # stripping of font not possible
122 for i
in range(len(self
.usedchars
)):
123 self
.usedchars
[i
] = self
.usedchars
[i
] or other
.usedchars
[i
]
125 def register(self
, registry
):
126 registry
.addresource(registry
.fontfiles
, self
)
128 def outputPS(self
, file):
129 file.write("%%%%BeginFont: %s\n" % self
.fontname
)
131 file.write("%Included char codes:")
132 for i
in range(len(self
.usedchars
)):
133 if self
.usedchars
[i
]:
134 file.write(" %d" % i
)
136 pfbpath
= pykpathsea
.find_file(self
.filename
, pykpathsea
.kpse_type1_format
)
138 raise RuntimeError("cannot find type 1 font %s" % self
.filename
)
140 if self
.encfilename
is not None:
141 encpath
= pykpathsea
.find_file(self
.encfilename
, pykpathsea
.kpse_tex_ps_header_format
)
143 raise RuntimeError("cannot find font encoding file %s" % self
.encfilename
)
144 t1strip
.t1strip(file, pfbpath
, self
.usedchars
, encpath
)
146 t1strip
.t1strip(file, pfbpath
, self
.usedchars
)
147 file.write("%%EndFont\n")
150 class PSfontencoding(PSresource
):
152 """ PostScript font encoding vector included in the prolog """
154 def __init__(self
, name
, filename
):
155 """ include font encoding vector specified by
157 - name: name of the encoding
158 - filename: name (without path) of file containing the font encoding
162 self
.type = "fontencoding"
163 self
.id = self
.name
= name
164 self
.filename
= filename
166 def register(self
, registry
):
167 registry
.addresource(registry
.fontencodings
, self
)
169 def outputPS(self
, file):
170 file.write("%%%%BeginProcSet: %s\n" % self
.name
)
171 path
= pykpathsea
.find_file(self
.filename
, pykpathsea
.kpse_tex_ps_header_format
)
172 encfile
= open(path
, "r")
173 file.write(encfile
.read())
175 file.write("%%EndProcSet\n")
178 class PSfontreencoding(PSresource
):
180 """ PostScript font re-encoding directive included in the prolog """
182 def __init__(self
, fontname
, basefontname
, encname
):
183 """ include font re-encoding directive specified by
185 - fontname: PostScript FontName of the new reencoded font
186 - basefontname: PostScript FontName of the original font
187 - encname: name of the encoding
188 - font: a reference to the font instance (temporarily added for pdf support)
190 Before being able to reencode a font, you have to include the
191 encoding via a fontencoding prolog item with name=encname
195 self
.type = "fontreencoding"
196 self
.id = self
.fontname
= fontname
197 self
.basefontname
= basefontname
198 self
.encname
= encname
200 def register(self
, registry
):
201 registry
.addresource(registry
.fontreencodings
, self
)
203 def outputPS(self
, file):
204 file.write("%%%%BeginProcSet: %s\n" % self
.fontname
)
205 file.write("/%s /%s %s ReEncodeFont\n" % (self
.basefontname
, self
.fontname
, self
.encname
))
206 file.write("%%EndProcSet\n")
209 _ReEncodeFont
= PSdefinition("ReEncodeFont", """{
212 /newencoding exch def
213 /newfontname exch def
214 /basefontname exch def
215 /basefontdict basefontname findfont def
216 /newfontdict basefontdict maxlength dict def
218 exch dup dup /FID ne exch /Encoding ne and
219 { exch newfontdict 3 1 roll put }
223 newfontdict /FontName newfontname put
224 newfontdict /Encoding newencoding put
225 newfontname newfontdict definefont pop
232 def __init__(self
, document
, filename
):
233 if len(document
.pages
) != 1:
234 raise ValueError("EPS file can be construced out of a single page document only")
235 page
= document
.pages
[0]
238 if filename
[-4:] != ".eps":
239 filename
= filename
+ ".eps"
241 file = open(filename
, "w")
243 raise IOError("cannot open output file")
246 bbox
.enlarge(page
.bboxenlarge
)
247 pagetrafo
= page
.pagetrafo(bbox
)
249 # if a page transformation is necessary, we have to adjust the bounding box
251 if pagetrafo
is not None:
252 bbox
.transform(pagetrafo
)
254 file.write("%!PS-Adobe-3.0 EPSF-3.0\n")
256 file.write("%%%%Creator: PyX %s\n" % version
.version
)
257 file.write("%%%%Title: %s\n" % filename
)
258 file.write("%%%%CreationDate: %s\n" %
259 time
.asctime(time
.localtime(time
.time())))
260 file.write("%%EndComments\n")
262 file.write("%%BeginProlog\n")
263 registry
= PSregistry()
264 for resource
in canvas
.resources():
265 resource
.PSregister(registry
)
266 registry
.outputPS(file)
267 file.write("%%EndProlog\n")
269 # apply a possible page transformation
270 if pagetrafo
is not None:
271 pagetrafo
.outputPS(file)
273 style
.linewidth
.normal
.outputPS(file)
275 # here comes the canvas content
276 canvas
.outputPS(file)
278 file.write("showpage\n")
279 file.write("%%Trailer\n")
280 file.write("%%EOF\n")
286 # def outputPS(self, file):
287 # file.write("%%%%PageMedia: %s\n" % self.paperformat)
288 # file.write("%%%%PageOrientation: %s\n" % (self.rotated and "Landscape" or "Portrait"))
289 # # file.write("%%%%PageBoundingBox: %d %d %d %d\n" % (math.floor(pbbox.llx_pt), math.floor(pbbox.lly_pt),
290 # # math.ceil(pbbox.urx_pt), math.ceil(pbbox.ury_pt)))
292 # # page setup section
293 # file.write("%%BeginPageSetup\n")
294 # file.write("/pgsave save def\n")
295 # # for scaling, we need the real bounding box of the page contents
296 # pbbox = canvas.bbox(self)
297 # pbbox.enlarge(self.bboxenlarge)
298 # ptrafo = calctrafo(pbbox, self.paperformat, self.margin, self.rotated, self.fittosize)
300 # ptrafo.outputPS(file)
301 # file.write("%f setlinewidth\n" % unit.topt(style.linewidth.normal))
302 # file.write("%%EndPageSetup\n")
304 # # here comes the actual content
305 # canvas.outputPS(self, file)
306 # file.write("pgsave restore\n")
307 # file.write("showpage\n")
308 # # file.write("%%PageTrailer\n")
311 # def writePSfile(self, filename):
312 # """write pages to PS file """
314 # if filename[-3:]!=".ps":
315 # filename = filename + ".ps"
318 # file = open(filename, "w")
320 # raise IOError("cannot open output file")
323 # for apage in self.pages:
324 # pbbox = apage.bbox()
325 # if docbbox is None:
331 # file.write("%!PS-Adobe-3.0\n")
332 # docbbox.outputPS(file)
333 # file.write("%%%%Creator: PyX %s\n" % version.version)
334 # file.write("%%%%Title: %s\n" % filename)
335 # file.write("%%%%CreationDate: %s\n" %
336 # time.asctime(time.localtime(time.time())))
337 # # required paper formats
339 # for apage in self.pages:
340 # if isinstance(apage, page):
341 # paperformats[apage.paperformat] = _paperformats[apage.paperformat]
343 # for paperformat, size in paperformats.items():
345 # file.write("%%DocumentMedia: ")
349 # file.write("%s %d %d 75 white ()\n" % (paperformat, unit.topt(size[0]), unit.topt(size[1])))
351 # file.write("%%%%Pages: %d\n" % len(self.pages))
352 # file.write("%%PageOrder: Ascend\n")
353 # file.write("%%EndComments\n")
355 # # document default section
356 # #file.write("%%BeginDefaults\n")
358 # # file.write("%%%%PageMedia: %s\n" % paperformat)
359 # #file.write("%%%%PageOrientation: %s\n" % (rotated and "Landscape" or "Portrait"))
360 # #file.write("%%EndDefaults\n")
362 # # document prolog section
363 # file.write("%%BeginProlog\n")
365 # for apage in self.pages:
366 # for pritem in apage.prolog():
367 # for mpritem in mergedprolog:
368 # if mpritem.merge(pritem) is None: break
370 # mergedprolog.append(pritem)
371 # for pritem in mergedprolog:
372 # pritem.outputPS(file)
373 # file.write("%%EndProlog\n")
375 # # document setup section
376 # #file.write("%%BeginSetup\n")
377 # #file.write("%%EndSetup\n")
380 # for nr, apage in enumerate(self.pages):
381 # file.write("%%%%Page: %s %d\n" % (apage.pagename is None and str(nr) or apage.pagename , nr+1))
382 # apage.outputPS(file)
384 # file.write("%%Trailer\n")
385 # file.write("%%EOF\n")