add (C) notice.
[mftrace.git] / tfm.py
blob7705e1f65677b23fb7bac26efa7864e82e0c7d9e
1 # part of
2 # mftrace - Generate Type1 or TrueType font from Metafont source.
4 # Copyright (c) 2001--2006 by
5 # Han-Wen Nienhuys, Jan Nieuwenhuizen
6 #
7 # Distributed under terms of the GNU General Public License. It comes with
8 # NO WARRANTY.
11 import sys
13 def compose_tfm_number (seq):
14 shift = (len (seq)-1)*8
16 cs = 0L
17 for b in seq:
18 cs = cs + (long (ord (b)) << shift)
19 shift = shift - 8
20 return cs
24 # Read params, ligatures, kernings.
27 class Tfm_reader:
28 def get_string (self):
29 b = ord (self.left[0])
30 s =self.left[1:1 + b]
31 self.left = self.left[1+b:]
33 return s
34 def get_byte (self):
35 b = self.left [0]
36 self.left= self.left[1:]
37 return ord(b)
39 def extract_fixps (self, count):
40 fs = [0.0] * count
42 for c in range (0,count):
43 fs[c] = self.get_fixp_number ()
45 return fs
47 def extract_chars (self):
48 count = self.end_code - self.start_code + 1
49 fs = [None] * count
51 for c in range (0,count):
52 w = self.get_byte()
53 b = self.get_byte()
54 h = (b & 0xf0) >> 4
55 d = (b & 0x0f)
57 b = self.get_byte ()
59 # huh? why >> 6 ?
60 i = (b & 0xfc) >> 6
61 tag = (b & 0x3)
62 rem = self.get_byte ()
64 # rem is used as index for the ligature table.
65 # TODO.
66 lig = None
68 fs[c] = (w, h, d, i, lig)
70 return fs
72 def get_ligatures(self):
73 return None
74 def get_kern_program (self):
75 return None
77 def __init__ (self, f):
78 self.string = f
79 self.left = f
81 self.file_length = self.get_number (2);
82 self.head_length = self.get_number (2);
83 self.start_code = self.get_number (2);
84 self.end_code = self.get_number (2);
85 self.width_count = self.get_number (2);
86 self.height_count =self.get_number(2);
87 self.depth_count = self.get_number (2);
88 self.italic_corr_count = self.get_number(2);
89 self.ligature_kern_count = self.get_number (2);
90 self.kern_count = self.get_number (2)
91 self.extensible_word_count =self.get_number (2);
92 self.parameter_count =self.get_number (2);
94 self.checksum = self.get_number (4)
95 self.design_size = self.get_fixp_number ()
96 self.coding = self.get_string ()
98 self.left =f[(6 + self.head_length) * 4:]
99 self.chars = self.extract_chars ()
100 self.widths = self.extract_fixps (self.width_count)
101 self.heights = self.extract_fixps (self.height_count)
102 self.depths = self.extract_fixps (self.depth_count)
103 self.italic_corrections = self.extract_fixps (self.italic_corr_count)
104 self.ligatures = self.get_ligatures ()
105 self.kern_program = self.get_kern_program()
107 del self.left
109 def get_number (self, len):
110 n = compose_tfm_number (self.left [0:len])
111 self.left = self.left[len:]
112 return n
114 def get_fixp_number (self):
115 n = self.get_number (4)
116 n = n /16.0 / (1<<16);
118 return n
120 def get_tfm (self):
121 keys = ['start_code', 'end_code', 'checksum', 'design_size', 'coding', 'chars', 'widths', 'heights', 'depths', 'italic_corrections', 'ligatures', 'kern_program']
122 tfm = Tex_font_metric ()
123 for k in keys:
124 tfm.__dict__[k] = self.__dict__[k]
125 return tfm
129 class Char_metric:
130 def __init__(self, tfm, tup):
131 (w, h, d, i, lig) = tup
132 ds = tfm.design_size
133 self.width = tfm.widths[w] *ds
134 self.height = tfm.heights[h] *ds
135 self.depth = tfm.depths [d] * ds
136 self.italic_correction = tfm.italic_corrections[i]*ds
140 class Tex_font_metric:
142 Bare bones wrapper around the TFM format.
146 def __init__ (self):
147 pass
149 def has_char (self, code):
150 if code < self.start_code or code > self.end_code:
151 return 0
153 tup = self.chars[code - self.start_code]
154 return tup[0] <> 0
156 def get_char (self,code):
157 tup = self.chars[code - self.start_code]
158 return Char_metric (self, tup)
160 def __str__ (self):
161 return r"""#<TFM file
162 char: %d, %d
163 checksum: %d
164 design_size: %f
165 coding: %s>""" % (self.start_code, self.end_code,
166 self.checksum, self.design_size, self.coding)
170 def read_tfm_file (fn):
171 reader =Tfm_reader (open (fn).read ())
172 return reader.get_tfm ()
174 if __name__=='__main__':
175 t = read_tfm_file (sys.argv[1])
176 print t, t.design_size, t.coding