normline_pt.curvature_pt should really return its result -- and changed some docstrings
[PyX/mjg.git] / pyx / type1font.py
blob6c0193fd745fc14ef947862d58920453c39f6d6e
1 #!/usr/bin/env python
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 import re, tempfile, os, binascii
25 try:
26 import zlib
27 except:
28 pass
29 import bbox, canvas, pswriter, pdfwriter
31 try:
32 enumerate([])
33 except NameError:
34 # fallback implementation for Python 2.2 and below
35 def enumerate(list):
36 return zip(xrange(len(list)), list)
39 # _PFB_ASCII = "\200\1"
40 # _PFB_BIN = "\200\2"
41 # _PFB_DONE = "\200\3"
42 # _PFA = "%!"
44 _StandardEncodingMatch = re.compile(r"\b/Encoding\s+StandardEncoding\s+def\b")
45 #_FontBBoxMatch = re.compile(r"\bFontBBox\s*\{\s*(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s*\}\s*readonly\s+def\b")
46 #_ItalicAngle = re.compile(r"\bItalicAngle\s+(-?\d+)\b")
49 def _pfblength(s):
50 if len(s) != 4:
51 raise ValueError("invalid string length")
52 return (ord(s[0]) +
53 ord(s[1])*256 +
54 ord(s[2])*256*256 +
55 ord(s[3])*256*256*256)
57 class _tokenfile:
58 """ ascii file containing tokens separated by spaces.
60 Comments beginning with % are ignored. Strings containing spaces
61 are not handled correctly
62 """
64 def __init__(self, filename):
65 self.file = open(filename, "r")
66 self.line = None
68 def gettoken(self):
69 """ return next token or None if EOF """
70 while not self.line:
71 line = self.file.readline()
72 if line == "":
73 return None
74 self.line = line.split("%")[0].split()
75 token = self.line[0]
76 self.line = self.line[1:]
77 return token
79 def close(self):
80 self.file.close()
83 class encoding:
85 def __init__(self, name, filename):
86 """ font encoding contained in filename """
87 self.name = name
88 self.filename = filename
91 class encodingfile:
93 def __init__(self, name, filename):
94 self.name = name
95 encfile = _tokenfile(filename)
97 # name of encoding
98 self.encname = encfile.gettoken()
99 token = encfile.gettoken()
100 if token != "[":
101 raise RuntimeError("cannot parse encoding file '%s', expecting '[' got '%s'" % (filename, token))
102 self.encvector = []
103 for i in range(256):
104 token = encfile.gettoken()
105 if token is None or token=="]":
106 raise RuntimeError("not enough charcodes in encoding file '%s'" % filename)
107 self.encvector.append(token)
108 if encfile.gettoken() != "]":
109 raise RuntimeError("too many charcodes in encoding file '%s'" % filename)
110 token = encfile.gettoken()
111 if token != "def":
112 raise RuntimeError("cannot parse encoding file '%s', expecting 'def' got '%s'" % (filename, token))
113 token = encfile.gettoken()
114 if token != None:
115 raise RuntimeError("encoding file '%s' too long" % filename)
116 encfile.close()
118 def decode(self, charcode):
119 return self.encvector[charcode]
121 def outputPS(self, file, writer, registry):
122 file.write("%%%%BeginProcSet: %s\n" % self.name)
123 file.write("/%s\n"
124 "[" % self.name)
125 for i, glyphname in enumerate(self.encvector):
126 if i and not (i % 8):
127 file.write("\n")
128 else:
129 file.write(" ")
130 file.write(glyphname)
131 file.write(" ] def\n"
132 "%%EndProcSet\n")
134 def outputPDF(self, file, writer, registry):
135 file.write("<<\n"
136 "/Type /Encoding\n"
137 "/Differences\n"
138 "[ 0")
139 for i, glyphname in enumerate(self.encvector):
140 if i and not (i % 8):
141 file.write("\n")
142 else:
143 file.write(" ")
144 file.write(glyphname)
145 file.write(" ]\n"
146 ">>\n")
149 class font:
151 def __init__(self, basefontname, filename, encoding, metric):
152 self.basefontname = basefontname
153 self.filename = filename
154 self.encoding = encoding
155 self.metric = metric
157 if encoding is None:
158 self.name = basefontname
159 else:
160 self.name = "%s-%s" % (basefontname, encoding.name)
163 class text_pt(canvas.canvasitem):
165 def __init__(self, x_pt, y_pt, font):
166 self.font = font
167 self.x_pt = x_pt
168 self.y_pt = y_pt
169 self.width_pt = 0
170 self.height_pt = 0
171 self.depth_pt = 0
172 self.chars = []
174 def addchar(self, char):
175 metric = self.font.metric
176 self.width_pt += metric.getwidth_pt(char)
177 cheight_pt = metric.getwidth_pt(char)
178 if cheight_pt > self.height_pt:
179 self.height_pt = cheight_pt
180 cdepth_pt = metric.getdepth_pt(char)
181 if cdepth_pt > self.depth_pt:
182 self.depth_pt = cdepth_pt
183 self.chars.append(char)
185 def bbox(self):
186 return bbox.bbox_pt(self.x_pt, self.y_pt-self.depth_pt, self.x_pt+self.width_pt, self.y_pt+self.height_pt)
188 def registerPS(self, registry):
189 # note that we don't register PSfont as it is just a helper resource
190 # which registers the needed components
191 pswriter.PSfont(self.font, self.chars, registry)
193 def registerPDF(self, registry):
194 registry.add(pdfwriter.PDFfont(self.font, self.chars, registry))
196 def outputPS(self, file, writer, context):
197 if ( context.font is None or
198 context.font.name != self.font.name or
199 context.font.metric.getsize_pt() != self.font.metric.getsize_pt() ):
200 file.write("/%s %f selectfont\n" % (self.font.name, self.font.metric.getsize_pt()))
201 context.font = self.font
202 outstring = ""
203 for char in self.chars:
204 if char > 32 and char < 127 and chr(char) not in "()[]<>\\":
205 ascii = "%s" % chr(char)
206 else:
207 ascii = "\\%03o" % char
208 outstring += ascii
209 file.write("%g %g moveto (%s) show\n" % (self.x_pt, self.y_pt, outstring))
212 def outputPDF(self, file, writer, context):
213 if ( context.font is None or
214 context.font.name != self.font.name or
215 context.font.metric.getsize_pt() != self.font.metric.getsize_pt() ):
216 file.write("/%s %f Tf\n" % (self.font.name, self.font.metric.getsize_pt()))
217 context.font = self.font
218 outstring = ""
219 for char in self.chars:
220 if 32 <= char <= 127 and chr(char) not in "()[]<>\\":
221 ascii = "%s" % chr(char)
222 else:
223 ascii = "\\%03o" % char
224 outstring += ascii
225 file.write("1 0 0 1 %f %f Tm (%s) Tj\n" % (self.x_pt, self.y_pt, outstring))