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
32 # in order to keep a consistent order of the registered resources we
33 # not only store them in a hash but also keep an ordered list (up to a
34 # possible merging of resources, in which case the first instance is
36 self
.resourceshash
= {}
37 self
.resourceslist
= []
39 def add(self
, resource
):
40 rkey
= (resource
.type, resource
.id)
41 if self
.resourceshash
.has_key(rkey
):
42 self
.resourceshash
[rkey
].merge(resource
)
44 self
.resourceshash
[rkey
] = resource
45 self
.resourceslist
.append(resource
)
47 def outputPS(self
, file):
48 """ write all PostScript code of the prolog resources """
49 for resource
in self
.resourceslist
:
50 resource
.outputPS(file)
58 """ a PostScript resource """
60 def __init__(self
, type, id):
61 # Every PSresource has to have a type and a unique id.
62 # Resources with the same type and id will be merged
63 # when they are registered in the PSregistry
67 def merge(self
, other
):
68 """ merge self with other, which has to be a resource of the same type and with
72 def outputPS(self
, file):
73 raise NotImplementedError("outputPS not implemented for %s" % repr(self
))
76 # Different variants of prolog items
79 class PSdefinition(PSresource
):
81 """ PostScript function definition included in the prolog """
83 def __init__(self
, id, body
):
84 self
.type = "definition"
88 def outputPS(self
, file):
89 file.write("%%%%BeginRessource: %s\n" % self
.id)
90 file.write("%(body)s /%(id)s exch def\n" % self
.__dict
__)
91 file.write("%%EndRessource\n")
94 class PSfontfile(PSresource
):
96 """ PostScript font definition included in the prolog """
98 def __init__(self
, fontname
, filename
, encfilename
, usedchars
):
99 """ include type 1 font defined by the following parameters
101 - fontname: PostScript FontName of font
102 - filename: name (without path) of file containing the font definition
103 - encfilename: name (without path) of file containing used encoding of font
104 or None (if no encoding file used)
105 - usechars: list with 256 elements containing used charcodes of font
109 # Note that here we only need the encoding for selecting the used glyphs!
113 self
.type = "fontfile"
114 self
.id = self
.fontname
= fontname
115 self
.filename
= filename
116 self
.encfilename
= encfilename
117 self
.usedchars
= usedchars
119 def merge(self
, other
):
120 if self
.encfilename
!= other
.encfilename
:
121 self
.usedchars
= None # stripping of font not possible
123 for i
in range(len(self
.usedchars
)):
124 self
.usedchars
[i
] = self
.usedchars
[i
] or other
.usedchars
[i
]
126 def outputPS(self
, file):
127 file.write("%%%%BeginFont: %s\n" % self
.fontname
)
129 file.write("%Included char codes:")
130 for i
in range(len(self
.usedchars
)):
131 if self
.usedchars
[i
]:
132 file.write(" %d" % i
)
134 pfbpath
= pykpathsea
.find_file(self
.filename
, pykpathsea
.kpse_type1_format
)
136 raise RuntimeError("cannot find type 1 font %s" % self
.filename
)
138 if self
.encfilename
is not None:
139 encpath
= pykpathsea
.find_file(self
.encfilename
, pykpathsea
.kpse_tex_ps_header_format
)
141 raise RuntimeError("cannot find font encoding file %s" % self
.encfilename
)
142 t1strip
.t1strip(file, pfbpath
, self
.usedchars
, encpath
)
144 t1strip
.t1strip(file, pfbpath
, self
.usedchars
)
145 file.write("%%EndFont\n")
148 class PSfontencoding(PSresource
):
150 """ PostScript font encoding vector included in the prolog """
152 def __init__(self
, name
, filename
):
153 """ include font encoding vector specified by
155 - name: name of the encoding
156 - filename: name (without path) of file containing the font encoding
160 self
.type = "fontencoding"
161 self
.id = self
.name
= name
162 self
.filename
= filename
164 def outputPS(self
, file):
165 file.write("%%%%BeginProcSet: %s\n" % self
.name
)
166 path
= pykpathsea
.find_file(self
.filename
, pykpathsea
.kpse_tex_ps_header_format
)
167 encfile
= open(path
, "r")
168 file.write(encfile
.read())
170 file.write("%%EndProcSet\n")
173 class PSfontreencoding(PSresource
):
175 """ PostScript font re-encoding directive included in the prolog """
177 def __init__(self
, fontname
, basefontname
, encname
):
178 """ include font re-encoding directive specified by
180 - fontname: PostScript FontName of the new reencoded font
181 - basefontname: PostScript FontName of the original font
182 - encname: name of the encoding
183 - font: a reference to the font instance (temporarily added for pdf support)
185 Before being able to reencode a font, you have to include the
186 encoding via a fontencoding prolog item with name=encname
190 self
.type = "fontreencoding"
191 self
.id = self
.fontname
= fontname
192 self
.basefontname
= basefontname
193 self
.encname
= encname
195 def outputPS(self
, file):
196 file.write("%%%%BeginProcSet: %s\n" % self
.fontname
)
197 file.write("/%s /%s %s ReEncodeFont\n" % (self
.basefontname
, self
.fontname
, self
.encname
))
198 file.write("%%EndProcSet\n")
201 _ReEncodeFont
= PSdefinition("ReEncodeFont", """{
204 /newencoding exch def
205 /newfontname exch def
206 /basefontname exch def
207 /basefontdict basefontname findfont def
208 /newfontdict basefontdict maxlength dict def
210 exch dup dup /FID ne exch /Encoding ne and
211 { exch newfontdict 3 1 roll put }
215 newfontdict /FontName newfontname put
216 newfontdict /Encoding newencoding put
217 newfontname newfontdict definefont pop
224 def __init__(self
, document
, filename
):
225 if len(document
.pages
) != 1:
226 raise ValueError("EPS file can be construced out of a single page document only")
227 page
= document
.pages
[0]
230 if filename
[-4:] != ".eps":
231 filename
= filename
+ ".eps"
233 file = open(filename
, "w")
235 raise IOError("cannot open output file")
238 bbox
.enlarge(page
.bboxenlarge
)
239 pagetrafo
= page
.pagetrafo(bbox
)
241 # if a page transformation is necessary, we have to adjust the bounding box
243 if pagetrafo
is not None:
244 bbox
.transform(pagetrafo
)
246 file.write("%!PS-Adobe-3.0 EPSF-3.0\n")
248 file.write("%%%%Creator: PyX %s\n" % version
.version
)
249 file.write("%%%%Title: %s\n" % filename
)
250 file.write("%%%%CreationDate: %s\n" %
251 time
.asctime(time
.localtime(time
.time())))
252 file.write("%%EndComments\n")
254 file.write("%%BeginProlog\n")
255 registry
= PSregistry()
256 for resource
in canvas
.resources():
257 resource
.PSregister(registry
)
258 registry
.outputPS(file)
259 file.write("%%EndProlog\n")
261 # apply a possible page transformation
262 if pagetrafo
is not None:
263 pagetrafo
.outputPS(file)
265 style
.linewidth
.normal
.outputPS(file)
267 # here comes the canvas content
268 canvas
.outputPS(file)
270 file.write("showpage\n")
271 file.write("%%Trailer\n")
272 file.write("%%EOF\n")
278 # def outputPS(self, file):
279 # file.write("%%%%PageMedia: %s\n" % self.paperformat)
280 # file.write("%%%%PageOrientation: %s\n" % (self.rotated and "Landscape" or "Portrait"))
281 # # file.write("%%%%PageBoundingBox: %d %d %d %d\n" % (math.floor(pbbox.llx_pt), math.floor(pbbox.lly_pt),
282 # # math.ceil(pbbox.urx_pt), math.ceil(pbbox.ury_pt)))
284 # # page setup section
285 # file.write("%%BeginPageSetup\n")
286 # file.write("/pgsave save def\n")
287 # # for scaling, we need the real bounding box of the page contents
288 # pbbox = canvas.bbox(self)
289 # pbbox.enlarge(self.bboxenlarge)
290 # ptrafo = calctrafo(pbbox, self.paperformat, self.margin, self.rotated, self.fittosize)
292 # ptrafo.outputPS(file)
293 # file.write("%f setlinewidth\n" % unit.topt(style.linewidth.normal))
294 # file.write("%%EndPageSetup\n")
296 # # here comes the actual content
297 # canvas.outputPS(self, file)
298 # file.write("pgsave restore\n")
299 # file.write("showpage\n")
300 # # file.write("%%PageTrailer\n")
303 # def writePSfile(self, filename):
304 # """write pages to PS file """
306 # if filename[-3:]!=".ps":
307 # filename = filename + ".ps"
310 # file = open(filename, "w")
312 # raise IOError("cannot open output file")
315 # for apage in self.pages:
316 # pbbox = apage.bbox()
317 # if docbbox is None:
323 # file.write("%!PS-Adobe-3.0\n")
324 # docbbox.outputPS(file)
325 # file.write("%%%%Creator: PyX %s\n" % version.version)
326 # file.write("%%%%Title: %s\n" % filename)
327 # file.write("%%%%CreationDate: %s\n" %
328 # time.asctime(time.localtime(time.time())))
329 # # required paper formats
331 # for apage in self.pages:
332 # if isinstance(apage, page):
333 # paperformats[apage.paperformat] = _paperformats[apage.paperformat]
335 # for paperformat, size in paperformats.items():
337 # file.write("%%DocumentMedia: ")
341 # file.write("%s %d %d 75 white ()\n" % (paperformat, unit.topt(size[0]), unit.topt(size[1])))
343 # file.write("%%%%Pages: %d\n" % len(self.pages))
344 # file.write("%%PageOrder: Ascend\n")
345 # file.write("%%EndComments\n")
347 # # document default section
348 # #file.write("%%BeginDefaults\n")
350 # # file.write("%%%%PageMedia: %s\n" % paperformat)
351 # #file.write("%%%%PageOrientation: %s\n" % (rotated and "Landscape" or "Portrait"))
352 # #file.write("%%EndDefaults\n")
354 # # document prolog section
355 # file.write("%%BeginProlog\n")
357 # for apage in self.pages:
358 # for pritem in apage.prolog():
359 # for mpritem in mergedprolog:
360 # if mpritem.merge(pritem) is None: break
362 # mergedprolog.append(pritem)
363 # for pritem in mergedprolog:
364 # pritem.outputPS(file)
365 # file.write("%%EndProlog\n")
367 # # document setup section
368 # #file.write("%%BeginSetup\n")
369 # #file.write("%%EndSetup\n")
372 # for nr, apage in enumerate(self.pages):
373 # file.write("%%%%Page: %s %d\n" % (apage.pagename is None and str(nr) or apage.pagename , nr+1))
374 # apage.outputPS(file)
376 # file.write("%%Trailer\n")
377 # file.write("%%EOF\n")