w32tex
About: TeX Live provides a comprehensive TeX system including all the major TeX-related programs, macro packages, and fonts that are free software. Windows sources.
  Fossies Dox: w32tex-src.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

mftrace.py
Go to the documentation of this file.
1 #! python
2 #
3 # this file is part of mftrace - a tool to generate scalable fonts from MF sources
4 #
5 
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License version 2
8 # as published by the Free Software Foundation
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Library General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc.,
18 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 
20 # Copyright (c) 2001--2006 by
21 # Han-Wen Nienhuys, Jan Nieuwenhuizen
22 
23 import os
24 import optparse
25 import sys
26 import re
27 import tempfile
28 import shutil
29 
30 prefix=''
31 
32 def interpolate (strng):
33  strng = strng.replace ('{', '(')
34  strng = strng.replace ('}', ')s')
35  strng = strng.replace ('$', '%')
36  return strng
37 
38 if prefix != '@' + 'prefix@':
39  prefix = os.popen ('kpsewhich -expand-var $SELFAUTODIR', 'r').read ()
40  prefix = prefix.replace('\n', '')
41  exec_prefix=prefix
42  datadir='%(prefix)s/share/mftrace' % vars()
43  libdir=datadir
44 
45 if datadir == '@' + "datadir" + "@":
46  datadir = os.getcwd ()
47  bindir = os.getcwd ()
48 
49 sys.path.append (datadir)
50 
51 import afm
52 import tfm
53 
54 errorport = sys.stderr
55 
56 ################################################################
57 # lilylib.py -- options and stuff
58 #
59 # source file of the GNU LilyPond music typesetter
60 
61 try:
62  import gettext
63  gettext.bindtextdomain ('mftrace', localedir)
64  gettext.textdomain ('mftrace')
65  _ = gettext.gettext
66 except:
67  def _ (s):
68  return s
69 
71  strng = re.sub ('([\'" ])', r'\\\1', strng)
72  return strng
73 
74 def identify (port):
75  port.write ('%s %s\n' % (program_name, program_version))
76 
77 def warranty ():
78  identify (sys.stdout)
79  sys.stdout.write ('\n')
80  sys.stdout.write (_ ('Copyright (c) %s by' % ' 2001--2004'))
81  sys.stdout.write ('\n')
82  sys.stdout.write (' Han-Wen Nienhuys')
83  sys.stdout.write (' Jan Nieuwenhuizen')
84  sys.stdout.write ('\n')
85  sys.stdout.write (_ (r'''
86 Distributed under terms of the GNU General Public License. It comes with
87 NO WARRANTY.'''))
88  sys.stdout.write ('\n')
89 
90 def progress (s):
91  errorport.write (s)
92 
93 def warning (s):
94  errorport.write (_ ("warning: ") + s)
95 
96 def error (s):
97  '''Report the error S and exit with an error status of 1.
98 
99  RETURN VALUE
100 
101  None
102 
103  '''
104 
105  errorport.write (_ ("error: ") + s + '\n')
106  errorport.write (_ ("Exiting ...") + '\n')
107  sys.exit(1)
108 
109 temp_dir = None
111  def __init__ (self, name=None):
112  import tempfile
113  if name:
114  if not os.path.isdir (name):
115  os.makedirs (name)
116  self.dirdir = name
117  else:
118  self.dirdir = tempfile.mkdtemp ()
119 
120  os.chdir (self.dirdir)
121 
122  def clean (self):
123  import shutil
124  shutil.rmtree (self.dirdir)
125  def __del__ (self):
126  self.cleanclean ()
127  def __call__ (self):
128  return self.dirdir
129  def __repr__ (self):
130  return self.dirdir
131  def __str__ (self):
132  return self.dirdir
133 
134 def setup_temp (name):
135  global temp_dir
136  if not temp_dir:
137  temp_dir = TempDirectory (name)
138  else:
139  os.chdir(temp_dir ())
140  return temp_dir ()
141 
142 def popen (cmd, mode = 'r', ignore_error = 0):
143  if options.verbose:
144  progress (_ ("Opening pipe `%s\'") % cmd)
145  pipe = os.popen (cmd, mode)
146  if options.verbose:
147  progress ('\n')
148  return pipe
149 
150 def system (cmd, ignore_error = 0):
151  """Run CMD. If IGNORE_ERROR is set, don't complain when CMD returns non zero.
152 
153  RETURN VALUE
154 
155  Exit status of CMD
156  """
157 
158  if options.verbose:
159  progress (_ ("Invoking `%s\'\n") % cmd)
160  st = os.system (cmd)
161  if st:
162  name = re.match ('[ \t]*([^ \t]*)', cmd).group (1)
163  msg = name + ': ' + _ ("command exited with value %d") % st
164  if ignore_error:
165  warning (msg + ' ' + _ ("(ignored)") + ' ')
166  else:
167  error (msg)
168  if options.verbose:
169  progress ('\n')
170  return st
171 
172 def strip_extension (f, ext):
173  (p, e) = os.path.splitext (f)
174  if e == ext:
175  e = ''
176  return p + e
177 
178 
179 ################################################################
180 # END Library
181 
182 
183 
184 options = None
185 exit_value = 0
186 backend_options = ''
187 program_name = 'mftrace'
188 temp_dir = None
189 program_version = '1.2.20'
190 origdir = os.getcwd ()
191 
192 coding_dict = {
193 
194  # from TeTeX
195  'TeX typewriter text': '09fbbfac.enc', # cmtt10
196  'TeX math symbols': '10037936.enc', # cmbsy
197  'ASCII caps and digits': '1b6d048e', # cminch
198  'TeX math italic': 'aae443f0.enc', # cmmi10
199  'TeX extended ASCII': 'd9b29452.enc',
200  'TeX text': 'f7b6d320.enc',
201  'TeX text without f-ligatures': '0ef0afca.enc',
202  'Extended TeX Font Encoding - Latin': 'tex256.enc',
203 
204  # LilyPond.
205  'fetaBraces': 'feta-braces-a.enc',
206  'fetaNumber': 'feta-nummer10.enc',
207  'fetaMusic': 'feta20.enc',
208  'parmesanMusic': 'parmesan20.enc',
209  }
210 
211 
212 def find_file (nm):
213  for d in include_dirs:
214  p = os.path.join (d, nm)
215  try:
216  open (p)
217  return os.path.abspath (p)
218  except IOError:
219  pass
220 
221  p = popen ('kpsewhich %s' % shell_escape_filename (nm)).read ()
222  p = p.strip ()
223 
224  if options.dos_kpath:
225  orig = p
226  p = p.lower ()
227  p = re.sub ('^([a-z]):', '/cygdrive/\\1', p)
228  p = re.sub ('\\\\', '/', p)
229  sys.stderr.write ("Got `%s' from kpsewhich, using `%s'\n" % (orig, p))
230  return p
231 
232 
233 def flag_error ():
234  global exit_value
235  exit_value = 1
236 
237 ################################################################
238 # TRACING.
239 ################################################################
240 
241 def autotrace_command (fn, opts):
242  opts = " " + opts + " --background-color=FFFFFF --output-format=eps --input-format=pbm "
243  return options.trace_binary + opts + backend_options \
244  + " --output-file=char.eps %s " % fn
245 
246 def potrace_command (fn, opts):
247  return options.trace_binary + opts \
248  + ' -u %d ' % options.grid_scale \
249  + backend_options \
250  + " -q -c --eps --output=char.eps %s " % (fn)
251 
252 trace_command = None
253 path_to_type1_ops = None
254 
255 def trace_one (pbmfile, id):
256  """
257  Run tracer, do error handling
258  """
259 
260  status = system (trace_command (pbmfile, ''), 1)
261 
262  if status == 2:
263  sys.stderr.write ("\nUser interrupt. Exiting\n")
264  sys.exit (2)
265 
266  if status == 0 and options.keep_temp_dir:
267  shutil.copy2 (pbmfile, '%s.pbm' % id)
268  shutil.copy2 ('char.eps', '%s.eps' % id)
269 
270  if status != 0:
271  error_file = os.path.join (origdir, 'trace-bug-%s.pbm' % id)
272  shutil.copy2 (pbmfile, error_file)
273  msg = """Trace failed on bitmap. Bitmap left in `%s\'
274 Failed command was:
275 
276  %s
277 
278 Please submit a bugreport to %s development.""" \
279  % (error_file, trace_command (error_file, ''), options.trace_binary)
280 
281  if options.keep_trying:
282  warning (msg)
283  sys.stderr.write ("\nContinuing trace...\n")
284  flag_error ()
285  else:
286  msg = msg + '\nRun mftrace with --keep-trying to produce a font anyway\n'
287  error (msg)
288  else:
289  return 1
290 
291  if status != 0:
292  warning ("Failed, skipping character.\n")
293  return 0
294  else:
295  return 1
296 
297 def make_pbm (filename, outname, char_number):
298  """ Extract bitmap from the PK file FILENAME (absolute) using `gf2pbm'.
299  Return FALSE if the glyph is not valid.
300  """
301 
302  command = "gf2pbm -n %d -o %s %s" % (char_number, outname, filename)
303  status = system (command, ignore_error = 1)
304  return (status == 0)
305 
306 def read_encoding (file):
307  sys.stderr.write (_ ("Using encoding file: `%s'\n") % file)
308 
309  strng = open (file).read ()
310  strng = re.sub ("%.*", '', strng)
311  strng = re.sub ("[\n\t \f]+", ' ', strng)
312  m = re.search ('/([^ ]+) \[([^\]]+)\] def', strng)
313  if not m:
314  error ("Encoding file is invalid")
315 
316  name = m.group (1)
317  cod = m.group (2)
318  cod = re.sub ('[ /]+', ' ', cod)
319  cods = cod.split ()
320 
321  return (name, cods)
322 
323 def zip_to_pairs (xs):
324  r = []
325  while xs:
326  r.append ((xs[0], xs[1]))
327  xs = xs[2:]
328  return r
329 
330 def unzip_pairs (tups):
331  lst = []
332  while tups:
333  lst = lst + list (tups[0])
334  tups = tups[1:]
335  return lst
336 
337 def autotrace_path_to_type1_ops (at_file, bitmap_metrics, tfm_wid, magnification):
338  inv_scale = 1000.0 / magnification
339 
340  (size_y, size_x, off_x, off_y) = list(map (lambda m, s = inv_scale: m * s,
341  bitmap_metrics))
342  ls = open (at_file).readlines ()
343  bbox = (10000, 10000, -10000, -10000)
344 
345  while ls and ls[0] != '*u\n':
346  ls = ls[1:]
347 
348  if ls == []:
349  return (bbox, '')
350 
351  ls = ls[1:]
352 
353  commands = []
354 
355 
356  while ls[0] != '*U\n':
357  ell = ls[0]
358  ls = ls[1:]
359 
360  toks = ell.split ()
361 
362  if len (toks) < 1:
363  continue
364  cmd = toks[-1]
365  args = list(map (lambda m, s = inv_scale: s * float (m),
366  toks[:-1]))
367  if options.round_to_int:
368  args = zip_to_pairs (list(map (round, args)))
369  else:
370  args = zip_to_pairs (args)
371  commands.append ((cmd, args))
372 
373  expand = {
374  'l': 'rlineto',
375  'm': 'rmoveto',
376  'c': 'rrcurveto',
377  'f': 'closepath',
378  }
379 
380  cx = 0
381  cy = size_y - off_y - inv_scale
382 
383  # t1asm seems to fuck up when using sbw. Oh well.
384  t1_outline = ' %d %d hsbw\n' % (- off_x, tfm_wid)
385  bbox = (10000, 10000, -10000, -10000)
386 
387  for (c, args) in commands:
388 
389  na = []
390  for a in args:
391  (nx, ny) = a
392  if c == 'l' or c == 'c':
393  bbox = update_bbox_with_point (bbox, a)
394 
395  na.append ((nx - cx, ny - cy))
396  (cx, cy) = (nx, ny)
397 
398  a = na
399  c = expand[c]
400  if options.round_to_int:
401  a = ['%d' % int (round (x)) for x in unzip_pairs (a)]
402  else:
403  a = ['%d %d div' \
404  % (int (round (x * options.grid_scale/inv_scale)),
405  int (round (options.grid_scale/inv_scale))) for x in unzip_pairs (a)]
406 
407  t1_outline = t1_outline + ' %s %s\n' % (' '.join (a), c)
408 
409  t1_outline = t1_outline + ' endchar '
410  t1_outline = '{\n %s } |- \n' % t1_outline
411 
412  return (bbox, t1_outline)
413 
414 # FIXME: Cut and paste programming
415 def potrace_path_to_type1_ops (at_file, bitmap_metrics, tfm_wid, magnification):
416  inv_scale = 1000.0 / magnification
417 
418  (size_y, size_x, off_x, off_y) = list(map (lambda m,
419  s = inv_scale: m * s,
420  bitmap_metrics))
421  ls = open (at_file).readlines ()
422  bbox = (10000, 10000, -10000, -10000)
423 
424  while ls and ls[0] != '0 setgray\n':
425  ls = ls[1:]
426 
427  if ls == []:
428  return (bbox, '')
429  ls = ls[1:]
430  commands = []
431 
432  while ls and ls[0] != 'grestore\n':
433  ell = ls[0]
434  ls = ls[1:]
435 
436  if ell == 'fill\n':
437  continue
438 
439  toks = ell.split ()
440 
441  if len (toks) < 1:
442  continue
443  cmd = toks[-1]
444  args = list(map (lambda m, s = inv_scale: s * float (m),
445  toks[:-1]))
446  args = zip_to_pairs (args)
447  commands.append ((cmd, args))
448 
449  # t1asm seems to fuck up when using sbw. Oh well.
450  t1_outline = ' %d %d hsbw\n' % (- off_x, tfm_wid)
451  bbox = (10000, 10000, -10000, -10000)
452 
453  # Type1 fonts have relative coordinates (doubly relative for
454  # rrcurveto), so must convert moveto and rcurveto.
455 
456  z = (0.0, size_y - off_y - 1.0)
457  for (c, args) in commands:
458  args = [(x[0] * (1.0 / options.grid_scale),
459  x[1] * (1.0 / options.grid_scale)) for x in args]
460 
461  if c == 'moveto':
462  args = [(args[0][0] - z[0], args[0][1] - z[1])]
463 
464  zs = []
465  for a in args:
466  lz = (z[0] + a[0], z[1] + a[1])
467  bbox = update_bbox_with_point (bbox, lz)
468  zs.append (lz)
469 
470  if options.round_to_int:
471  last_discr_z = (int (round (z[0])), int (round (z[1])))
472  else:
473  last_discr_z = (z[0], z[1])
474  args = []
475  for a in zs:
476  if options.round_to_int:
477  a = (int (round (a[0])), int (round (a[1])))
478  else:
479  a = (a[0], a[1])
480  args.append ((a[0] - last_discr_z[0],
481  a[1] - last_discr_z[1]))
482 
483  last_discr_z = a
484 
485  if zs:
486  z = zs[-1]
487 
488  c = {
489  'closepath': 'closepath',
490  'moveto': 'rmoveto',
491  'rcurveto': 'rrcurveto',
492  # Potrace 1.9
493  'restore': '',
494  'rlineto': 'rlineto',
495  '%%EOF': '',
496  }[c]
497 
498  if c == 'rmoveto':
499  t1_outline += ' closepath '
500 
501  if options.round_to_int:
502  args = ['%d' % int (round (x)) for x in unzip_pairs (args)]
503  else:
504  args = ['%d %d div' \
505  % (int (round (x*options.grid_scale/inv_scale)),
506  int (round (options.grid_scale/inv_scale))) for x in unzip_pairs (args)]
507 
508  t1_outline = t1_outline + ' %s %s\n' % (' '.join (args), c)
509 
510  t1_outline = t1_outline + ' endchar '
511  t1_outline = '{\n %s } |- \n' % t1_outline
512 
513  return (bbox, t1_outline)
514 
515 def read_gf_dims (name, c):
516  strng = popen ('gf2pbm -n %d -s %s' % (c, name)).read ()
517  m = re.search ('size: ([0-9]+)+x([0-9]+), offset: \‍(([0-9-]+),([0-9-]+)\‍)', strng)
518 
519  return tuple (map (int, m.groups ()))
520 
521 def trace_font (fontname, gf_file, metric, glyphs, encoding,
522  magnification, fontinfo):
523  t1os = []
524  font_bbox = (10000, 10000, -10000, -10000)
525 
526  progress (_ ("Tracing bitmaps..."))
527 
528  if options.verbose:
529  progress ('\n')
530  else:
531  progress (' ')
532 
533  # for single glyph testing.
534  # glyphs = []
535  for a in glyphs:
536  if encoding[a] == ".notavail":
537  continue
538  valid = metric.has_char (a)
539  if not valid:
540  encoding[a] = ".notavail"
541  continue
542 
543  valid = make_pbm (gf_file, 'char.pbm', a)
544  if not valid:
545  encoding[a] = ".notavail"
546  continue
547 
548  (w, h, xo, yo) = read_gf_dims (gf_file, a)
549 
550  if not options.verbose:
551  sys.stderr.write ('[%d' % a)
552  sys.stderr.flush ()
553 
554  # this wants the id, not the filename.
555  success = trace_one ("char.pbm", '%s-%d' % (options.gffile, a))
556  if not success:
557  sys.stderr.write ("(skipping character)]")
558  sys.stderr.flush ()
559  encoding[a] = ".notavail"
560  continue
561 
562  if not options.verbose:
563  sys.stderr.write (']')
564  sys.stderr.flush ()
565  metric_width = metric.get_char (a).width
566  tw = int (round (metric_width / metric.design_size * 1000))
567  (bbox, t1o) = path_to_type1_ops ("char.eps", (h, w, xo, yo),
568  tw, magnification)
569 
570  if t1o == '':
571  encoding[a] = ".notavail"
572  continue
573 
574  font_bbox = update_bbox_with_bbox (font_bbox, bbox)
575 
576  t1os.append ('\n/%s %s ' % (encoding[a], t1o))
577 
578  if not options.verbose:
579  progress ('\n')
580  to_type1 (t1os, font_bbox, fontname, encoding, magnification, fontinfo)
581 
582 def ps_encode_encoding (encoding):
583  strng = ' %d array\n0 1 %d {1 index exch /.notdef put} for\n' \
584  % (len (encoding), len (encoding)-1)
585 
586  for i in range (0, len (encoding)):
587  if encoding[i] != ".notavail":
588  strng = strng + 'dup %d /%s put\n' % (i, encoding[i])
589 
590  return strng
591 
592 
593 def gen_unique_id (dict):
594  nm = 'FullName'
595  return 4000000 + (hash (nm) % 1000000)
596 
597 def to_type1 (outlines, bbox, fontname, encoding, magnification, fontinfo):
598 
599  """
600  Fill in the header template for the font, append charstrings,
601  and shove result through t1asm
602  """
603  template = r"""%%!PS-AdobeFont-1.0: %(FontName)s %(VVV)s.%(WWW)s
604 13 dict begin
605 /FontInfo 16 dict dup begin
606 /version (%(VVV)s.%(WWW)s) readonly def
607 /Notice (%(Notice)s) readonly def
608 /FullName (%(FullName)s) readonly def
609 /FamilyName (%(FamilyName)s) readonly def
610 /Weight (%(Weight)s) readonly def
611 /ItalicAngle %(ItalicAngle)s def
612 /isFixedPitch %(isFixedPitch)s def
613 /UnderlinePosition %(UnderlinePosition)s def
614 /UnderlineThickness %(UnderlineThickness)s def
615 end readonly def
616 /FontName /%(FontName)s def
617 /FontType 1 def
618 /PaintType 0 def
619 /FontMatrix [%(xrevscale)f 0 0 %(yrevscale)f 0 0] readonly def
620 /FontBBox {%(llx)d %(lly)d %(urx)d %(ury)d} readonly def
621 /Encoding %(Encoding)s readonly def
622 currentdict end
623 currentfile eexec
624 dup /Private 20 dict dup begin
625 /-|{string currentfile exch readstring pop}executeonly def
626 /|-{noaccess def}executeonly def
627 /|{noaccess put}executeonly def
628 /lenIV 4 def
629 /password 5839 def
630 /MinFeature {16 16} |-
631 /BlueValues [] |-
632 /OtherSubrs [ {} {} {} {} ] |-
633 /ForceBold false def
634 /Subrs 1 array
635 dup 0 { return } |
636 |-
637 2 index
638 /CharStrings %(CharStringsLen)d dict dup begin
639 %(CharStrings)s
640 
641 
642 /.notdef { 0 0 hsbw endchar } |-
643 end
644 end
645 readonly put
646 noaccess put
647 dup/FontName get exch definefont
648 pop mark currentfile closefile
649 cleartomark
650 """
651 ## apparently, some fonts end the file with cleartomark. Don't know why.
652 
653  copied_fields = ['FontName', 'FamilyName', 'FullName', 'DesignSize',
654  'ItalicAngle', 'isFixedPitch', 'Weight']
655 
656  vars = {
657  'VVV': '001',
658  'WWW': '001',
659  'Notice': 'Generated from MetaFont bitmap by mftrace %s, http://www.xs4all.nl/~hanwen/mftrace/ ' % program_version,
660  'UnderlinePosition': '-100',
661  'UnderlineThickness': '50',
662  'xrevscale': 1.0/1000.0,
663  'yrevscale': 1.0/1000.0,
664  'llx': bbox[0],
665  'lly': bbox[1],
666  'urx': bbox[2],
667  'ury': bbox[3],
668  'Encoding': ps_encode_encoding (encoding),
669 
670  # need one extra entry for .notdef
671  'CharStringsLen': len (outlines) + 1,
672  'CharStrings': ' '.join (outlines),
673  'CharBBox': '0 0 0 0',
674  }
675 
676  for k in copied_fields:
677  vars[k] = fontinfo[k]
678 
679  open ('mftrace.t1asm', 'w').write (template % vars)
680 
681 def update_bbox_with_point (bbox, pt):
682  (llx, lly, urx, ury) = bbox
683  llx = min (pt[0], llx)
684  lly = min (pt[1], lly)
685  urx = max (pt[0], urx)
686  ury = max (pt[1], ury)
687 
688  return (llx, lly, urx, ury)
689 
690 def update_bbox_with_bbox (bb, dims):
691  (llx, lly, urx, ury) = bb
692  llx = min (llx, dims[0])
693  lly = min (lly, dims[1])
694  urx = max (urx, dims[2])
695  ury = max (ury, dims[3])
696 
697  return (llx, lly, urx, ury)
698 
699 def get_binary (name):
700  search_path = os.environ['PATH'].split (';')
701  for p in search_path:
702  nm = os.path.join (p, name)
703  if os.path.exists (nm):
704  return nm
705 
706  return ''
707 
709  if get_binary('fontforge.exe'):
710  pass
711  else:
712  return ''
713 
714  stat = system ("fontforge.exe --help > pfv 2>&1 ",
715  ignore_error = 1)
716 
717  if stat != 0:
718  warning ("Command `fontforge.exe --help' failed. Cannot simplify or convert to TTF.\n")
719  return ''
720 
721  return 'fontforge.exe'
722 
723 def tfm2kpx (tfmname, encoding):
724  kpx_lines = []
725  pl = popen ("tftopl %s" % (tfmname))
726 
727  label_pattern = re.compile (
728  "\A \‍(LABEL ([DOHC]{1}) ([A-Za-z0-9]*)\‍)")
729  krn_pattern = re.compile (
730  "\A \‍(KRN ([DOHC]{1}) ([A-Za-z0-9]*) R (-?[\d\.]+)\‍)")
731 
732  first = 0
733  second = 0
734 
735  for line in pl.readlines ():
736 
737  label_match = label_pattern.search (line)
738  if not (label_match is None):
739  if label_match.group (1) == "D":
740  first = int (label_match.group (2))
741  elif label_match.group (1) == "O":
742  first = int (label_match.group (2), 8)
743  elif label_match.group (1) == "C":
744  first = ord (label_match.group (2))
745 
746  krn_match = krn_pattern.search (line)
747  if not (krn_match is None):
748  if krn_match.group (1) == "D":
749  second = int (krn_match.group (2))
750  elif krn_match.group (1) == "O":
751  second = int (krn_match.group (2), 8)
752  elif krn_match.group (1) == "C":
753  second = ord (krn_match.group (2))
754 
755  krn = round (float (krn_match.group (3)) * 1000)
756 
757  if (encoding[first] != '.notavail' and
758  encoding[first] != '.notdef' and
759  encoding[second] != '.notavail' and
760  encoding[second] != '.notdef'):
761 
762  kpx_lines.append ("KPX %s %s %d\n" % (
763  encoding[first], encoding[second], krn))
764 
765  return kpx_lines
766 
767 def get_afm (t1_path, tfmname, encoding, out_path):
768  afm_stream = popen ("printafm %s" % (t1_path))
769  afm_lines = []
770  kpx_lines = tfm2kpx (tfmname, encoding)
771 
772  for line in afm_stream.readlines ():
773  afm_lines.append (line)
774 
775  if re.match (r"^EndCharMetrics", line, re.I):
776  afm_lines.append ("StartKernData\n")
777  afm_lines.append ("StartKernPairs %d\n" % len (kpx_lines))
778 
779  for kpx_line in kpx_lines:
780  afm_lines.append (kpx_line)
781 
782  afm_lines.append ("EndKernPairs\n")
783  afm_lines.append ("EndKernData\n")
784 
785  progress (_ ("Writing metrics to `%s'... ") % out_path)
786  afm_file = open (out_path, 'wb')
787  afm_file.writelines (afm_lines)
788  afm_file.flush ()
789  afm_file.close ()
790 
791  progress ('\n')
792 
793 def assemble_font (fontname, format, is_raw):
794  ext = '.' + format
795  asm_opt = '--pfa'
796 
797  if format == 'pfb':
798  asm_opt = '--pfb'
799 
800  if is_raw:
801  ext = ext + '.raw'
802 
803  outname = fontname + ext
804 
805  progress (_ ("Assembling raw font to `%s'... ") % outname)
806  if options.verbose:
807  progress ('\n')
808  system ("t1asm %s mftrace.t1asm %s" % (asm_opt, shell_escape_filename (outname)))
809  progress ('\n')
810  return outname
811 
812 def make_outputs (fontname, formats, encoding):
813  """
814  run fontforge to convert to other formats
815  """
816 
817  ff_needed = 0
818  ff_command = ""
819 
820  if (options.simplify or options.round_to_int or 'ttf' in formats or 'svg' in formats or 'afm' in formats):
821  ff_needed = 1
822  if ff_needed:
823  ff_command = get_fontforge_command ()
824 
825  if ff_needed and ff_command:
826  raw_name = assemble_font (fontname, 'pfa', 1)
827 
828  simplify_cmd = ''
829  if options.round_to_int:
830  simplify_cmd = 'RoundToInt ();'
831  generate_cmds = ''
832  for f in formats:
833  generate_cmds += 'Generate("%s");' % (fontname + '.' + f)
834 
835  if options.simplify:
836  simplify_cmd ='''SelectAll ();
837 
838 AddExtrema();
839 Simplify ();
840 %(simplify_cmd)s
841 AutoHint ();''' % vars()
842 
843  pe_script = ('''#!/usr/bin/env %(ff_command)s
844 Open ($1);
845 MergeKern($2);
846 %(simplify_cmd)s
847 %(generate_cmds)s
848 Quit (0);
849 ''' % vars())
850 
851  open ('to-ttf.pe', 'w').write (pe_script)
852  if options.verbose:
853  print('Fontforge script', pe_script)
854  system ("fontforge.exe -quiet -script to-ttf.pe %s %s" %
855  (shell_escape_filename (raw_name), shell_escape_filename (options.tfm_file)))
856  elif ff_needed and (options.simplify or options.round_to_int or 'ttf' in formats or 'svg' in formats):
857  error(_ ("fontforge is not installed; could not perform requested command"))
858  else:
859  t1_path = ''
860 
861  if ('pfa' in formats):
862  t1_path = assemble_font (fontname, 'pfa', 0)
863 
864  if ('pfb' in formats):
865  t1_path = assemble_font (fontname, 'pfb', 0)
866 
867  if (t1_path != '' and 'afm' in formats):
868  if get_binary("printafm"):
869  get_afm (t1_path, options.tfm_file, encoding, fontname + '.afm')
870  else:
871  error(_ ("Neither fontforge nor ghostscript is installed; could not perform requested command"))
872 
873 
874 def getenv (var, default):
875  if var in os.environ:
876  return os.environ[var]
877  else:
878  return default
879 
880 def gen_pixel_font (filename, metric, magnification):
881  """
882  Generate a GF file for FILENAME, such that `magnification'*mfscale
883  (default 1000 * 1.0) pixels fit on the designsize.
884  """
885  base_dpi = 1200
886 
887  size = metric.design_size
888 
889  size_points = size * 1/72.27 * base_dpi
890 
891  mag = magnification / size_points
892 
893  prod = mag * base_dpi
894  try:
895  open ('%s.%dgf' % (filename, prod))
896  except IOError:
897  ## MFINPUTS/TFMFONTS take kpathsea specific values;
898  ## we should analyse them any further.
899  os.environ['KPSE_DOT'] = '%s;' % origdir
900  os.environ['MFINPUTS'] = '%s;%s' % (origdir,
901  getenv ('MFINPUTS', ''))
902  os.environ['TFMFONTS'] = '%s;%s' % (origdir,
903  getenv ('TFMINPUTS', ''))
904  progress (_ ("Running Metafont..."))
905 
906  cmdstr = r'mf-nowin --progname=mf --base=mf "\mode:=ultre; mag:=%f; nonstopmode; input %s"' % (mag, filename)
907  if not options.verbose:
908  cmdstr = cmdstr + ' 1>nul 2>nul'
909  st = system (cmdstr, ignore_error = 1)
910  progress ('\n')
911 
912  logfile = '%s.log' % filename
913  log = ''
914  prod = 0
915  if os.path.exists (logfile):
916  log = open (logfile).read ()
917  m = re.search ('Output written on %s.([0-9]+)gf' % re.escape (filename), log)
918  prod = int (m.group (1))
919 
920  if st:
921  sys.stderr.write ('\n\nMetafont failed. Excerpt from the log file: \n\n*****')
922  m = re.search ("\n!", log)
923  start = m.start (0)
924  short_log = log[start:start+200]
925  sys.stderr.write (short_log)
926  sys.stderr.write ('\n*****\n')
927  if re.search ('Arithmetic overflow', log):
928  sys.stderr.write ("""
929 
930 Apparently, some numbers overflowed. Try using --magnification with a
931 lower number. (Current magnification: %d)
932 """ % magnification)
933 
934  if not options.keep_trying or prod == 0:
935  sys.exit (1)
936  else:
937  sys.stderr.write ('\n\nTrying to proceed despite of the Metafont errors...\n')
938 
939 
940 
941  return "%s.%d" % (filename, prod)
942 
944  p = optparse.OptionParser (version="""mftrace 1.2.20
945 
946 This program is free software. It is covered by the GNU General Public
947 License and you are welcome to change it and/or distribute copies of it
948 under certain conditions. Invoke as `mftrace --warranty' for more
949 information.
950 
951 Copyright (c) 2005--2006 by
952  Han-Wen Nienhuys <hanwen@xs4all.nl>
953 
954 """)
955  p.usage = "mftrace [OPTION]... FILE..."
956  p.description = _ ("Generate Type1 or TrueType font from Metafont source.")
957 
958  p.add_option ('-k', '--keep',
959  action="store_true",
960  dest="keep_temp_dir",
961  help=_ ("Keep all output in directory %s.dir") % program_name)
962  p.add_option ('--magnification',
963  dest="magnification",
964  metavar="MAG",
965  default=1000.0,
966  type="float",
967  help=_("Set magnification for MF to MAG (default: 1000)"))
968  p.add_option ('-V', '--verbose',
969  action='store_true',
970  default=False,
971  help=_ ("Be verbose"))
972  p.add_option ('-f', '--formats',
973  action="append",
974  dest="formats",
975  default=[],
976  help=_("Which formats to generate (choices: AFM, PFA, PFB, TTF, SVG)"))
977  p.add_option ('--simplify',
978  action="store_true",
979  dest="simplify",
980  default=False,
981  help=_ ("Simplify using fontforge"))
982  p.add_option ('--gffile',
983  dest="gffile",
984  help= _("Use gf FILE instead of running Metafont"))
985  p.add_option ('-I', '--include',
986  dest="include_dirs",
987  action="append",
988  default=[],
989  help=_("Add to path for searching files"))
990  p.add_option ('--glyphs',
991  default=[],
992  action="append",
993  dest="glyphs",
994  metavar="LIST",
995  help= _('Process only these glyphs. LIST is comma separated'))
996  p.add_option ('--tfmfile',
997  metavar='FILE',
998  action='store',
999  dest='tfm_file')
1000  p.add_option ('-e', '--encoding',
1001  metavar="FILE",
1002  action='store',
1003  dest="encoding_file",
1004  default="",
1005  help= _ ("Use encoding file FILE"))
1006  p.add_option ('--keep-trying',
1007  dest='keep_trying',
1008  default=False,
1009  action="store_true",
1010  help= _ ("Don't stop if tracing fails"))
1011  p.add_option ('-w', '--warranty',
1012  action="store_true",
1013  help=_ ("show warranty and copyright"))
1014  p.add_option ('--dos-kpath',
1015  action='store_true',
1016  dest="dos_kpath",
1017  help=_("try to use Miktex kpsewhich"))
1018  p.add_option ('--potrace',
1019  action='store_true',
1020  dest='potrace',
1021  help=_ ("Use potrace"))
1022  p.add_option ('--autotrace',
1023  action='store_true',
1024  dest='autotrace',
1025  help=_ ("Use autotrace"))
1026  p.add_option ('--no-afm',
1027  action='store_false',
1028  dest="read_afm",
1029  default=True,
1030  help=_("Don't read AFM file"))
1031  p.add_option ('--noround',
1032  action='store_false',
1033  dest='round_to_int',
1034  default=True,
1035  help=_("Do not round coordinates of control points to integer values (use with --grid)"))
1036  p.add_option ('--grid',
1037  metavar='SCALE',
1038  dest='grid_scale',
1039  type='float',
1040  default = 1.0,
1041  help=_ ("Set reciprocal grid size in em units"))
1042  p.add_option ('-D','--define',
1043  metavar="SYMBOL=VALUE",
1044  dest="defs",
1045  default=[],
1046  action='append',help=_("Set the font info SYMBOL to VALUE"))
1047 
1048  global options
1049  (options, files) = p.parse_args ()
1050 
1051  if not files:
1052  sys.stderr.write ('Need argument on command line \n')
1053  p.print_help ()
1054  sys.exit (2)
1055 
1056  if options.warranty :
1057  warranty ()
1058  sys.exit (0)
1059 
1060  options.font_info = {}
1061  for d in options.defs:
1062  kv = d.split('=')
1063  if len (kv) == 1:
1064  options.font_info[kv] = 'true'
1065  elif len (kv) > 1:
1066  options.font_info[kv[0]] = '='.join (kv[1:])
1067 
1068  def comma_sepped_to_list (x):
1069  fs = []
1070  for f in x:
1071  fs += f.lower ().split (',')
1072  return fs
1073 
1074  options.formats = comma_sepped_to_list (options.formats)
1075 
1076  new_glyphs = []
1077  for r in options.glyphs:
1078  new_glyphs += r.split (',')
1079  options.glyphs = new_glyphs
1080 
1081  glyph_range = []
1082  for r in options.glyphs:
1083  glyph_subrange = list(map (int, r.split('-')))
1084  if len (glyph_subrange) == 2 and glyph_subrange[0] < glyph_subrange[1] + 1:
1085  glyph_range += list(range(glyph_subrange[0], glyph_subrange[1] + 1))
1086  else:
1087  glyph_range.append (glyph_subrange[0])
1088 
1089  options.glyphs = glyph_range
1090 
1091  options.trace_binary = ''
1092  if options.potrace:
1093  options.trace_binary = 'potrace'
1094  elif options.autotrace:
1095  options.trace_binary = 'autotrace'
1096 
1097  if options.formats == []:
1098  options.formats = ['pfa']
1099 
1100 
1101 
1102  global trace_command
1103  global path_to_type1_ops
1104 
1105  stat = os.system ('potrace --version > nul 2>&1 ')
1106  if options.trace_binary != 'autotrace' and stat == 0:
1107  options.trace_binary = 'potrace'
1108 
1109  trace_command = potrace_command
1110  path_to_type1_ops = potrace_path_to_type1_ops
1111  elif options.trace_binary == 'potrace' and stat != 0:
1112  error (_ ("Could not run potrace; have you installed it?"))
1113 
1114  stat = os.system ('autotrace --version > nul 2>&1 ')
1115  if options.trace_binary != 'potrace' and stat == 0:
1116  options.trace_binary = 'autotrace'
1117  trace_command = autotrace_command
1118  path_to_type1_ops = autotrace_path_to_type1_ops
1119  elif options.trace_binary == 'autotrace' and stat != 0:
1120  error (_ ("Could not run autotrace; have you installed it?"))
1121 
1122  if not options.trace_binary:
1123  error (_ ("No tracing program found.\nInstall potrace or autotrace."))
1124 
1125  return files
1126 
1127 
1128 def derive_font_name (family, fullname):
1129  fullname = re.sub (family, '', fullname)
1130  family = re.sub (' ', '', family)
1131  fullname = re.sub ('Oldstyle Figures', 'OsF', fullname)
1132  fullname = re.sub ('Small Caps', 'SC', fullname)
1133  fullname = re.sub ('[Mm]edium', '', fullname)
1134  fullname = re.sub ('[^A-Za-z0-9]', '', fullname)
1135  return '%s-%s' % (family, fullname)
1136 
1137 def cm_guess_font_info (filename, fontinfo):
1138  # urg.
1139  filename = re.sub ("cm(.*)tt", r"cmtt\1", filename)
1140  m = re.search ("([0-9]+)$", filename)
1141  design_size = ''
1142  if m:
1143  design_size = int (m.group (1))
1144  fontinfo['DesignSize'] = design_size
1145 
1146  prefixes = [("cmtt", "Computer Modern Typewriter"),
1147  ("cmvtt", "Computer Modern Variable Width Typewriter"),
1148  ("cmss", "Computer Modern Sans"),
1149  ("cm", "Computer Modern")]
1150 
1151  family = ''
1152  for (k, v) in prefixes:
1153  if re.search (k, filename):
1154  family = v
1155  if k == 'cmtt':
1156  fontinfo['isFixedPitch'] = 'true'
1157  filename = re.sub (k, '', filename)
1158  break
1159 
1160  # shapes
1161  prefixes = [("r", "Roman"),
1162  ("mi", "Math italic"),
1163  ("u", "Unslanted italic"),
1164  ("sl", "Oblique"),
1165  ("csc", "Small Caps"),
1166  ("ex", "Math extension"),
1167  ("ti", "Text italic"),
1168  ("i", "Italic")]
1169  shape = ''
1170  for (k, v) in prefixes:
1171  if re.search (k, filename):
1172  shape = v
1173  filename = re.sub (k, '', filename)
1174 
1175  prefixes = [("b", "Bold"),
1176  ("d", "Demi bold")]
1177  weight = 'Regular'
1178  for (k, v) in prefixes:
1179  if re.search (k, filename):
1180  weight = v
1181  filename = re.sub (k, '', filename)
1182 
1183  prefixes = [("c", "Condensed"),
1184  ("x", "Extended")]
1185  stretch = ''
1186  for (k, v) in prefixes:
1187  if re.search (k, filename):
1188  stretch = v
1189  filename = re.sub (k, '', filename)
1190 
1191  fontinfo['ItalicAngle'] = 0
1192  if re.search ('[Ii]talic', shape) or re.search ('[Oo]blique', shape):
1193  a = -14
1194  if re.search ("Sans", family):
1195  a = -12
1196 
1197  fontinfo ["ItalicAngle"] = a
1198 
1199  fontinfo['Weight'] = weight
1200  fontinfo['FamilyName'] = family
1201  full = '%s %s %s %s %dpt' \
1202  % (family, shape, weight, stretch, design_size)
1203  full = re.sub (" +", ' ', full)
1204 
1205  fontinfo['FullName'] = full
1206  fontinfo['FontName'] = derive_font_name (family, full)
1207 
1208  return fontinfo
1209 
1210 def ec_guess_font_info (filename, fontinfo):
1211  design_size = 12
1212  m = re.search ("([0-9]+)$", filename)
1213  if m:
1214  design_size = int (m.group (1))
1215  fontinfo['DesignSize'] = design_size
1216 
1217  prefixes = [("ecss", "European Computer Modern Sans"),
1218  ("ectt", "European Computer Modern Typewriter"),
1219  ("ec", "European Computer Modern")]
1220 
1221  family = ''
1222  for (k, v) in prefixes:
1223  if re.search (k, filename):
1224  if k == 'ectt':
1225  fontinfo['isFixedPitch'] = 'true'
1226  family = v
1227  filename = re.sub (k, '', filename)
1228  break
1229 
1230  # shapes
1231  prefixes = [("r", "Roman"),
1232  ("mi", "Math italic"),
1233  ("u", "Unslanted italic"),
1234  ("sl", "Oblique"),
1235  ("cc", "Small caps"),
1236  ("ex", "Math extension"),
1237  ("ti", "Italic"),
1238  ("i", "Italic")]
1239 
1240  shape = ''
1241  for (k, v) in prefixes:
1242  if re.search (k, filename):
1243  shape = v
1244  filename = re.sub (k, '', filename)
1245 
1246  prefixes = [("b", "Bold"),
1247  ("d", "Demi bold")]
1248  weight = 'Regular'
1249  for (k, v) in prefixes:
1250  if re.search (k, filename):
1251  weight = v
1252  filename = re.sub (k, '', filename)
1253 
1254  prefixes = [("c", "Condensed"),
1255  ("x", "Extended")]
1256  stretch = ''
1257  for (k, v) in prefixes:
1258  if re.search (k, filename):
1259  stretch = v
1260  filename = re.sub (k, '', filename)
1261 
1262  fontinfo['ItalicAngle'] = 0
1263  if re.search ('[Ii]talic', shape) or re.search ('[Oo]blique', shape):
1264  a = -14
1265  if re.search ("Sans", family):
1266  a = -12
1267 
1268  fontinfo ["ItalicAngle"] = a
1269 
1270  fontinfo['Weight'] = weight
1271  fontinfo['FamilyName'] = family
1272  full = '%s %s %s %s %dpt' \
1273  % (family, shape, weight, stretch, design_size)
1274  full = re.sub (" +", ' ', full)
1275 
1276  fontinfo['FontName'] = derive_font_name (family, full)
1277  fontinfo['FullName'] = full
1278 
1279  return fontinfo
1280 
1281 
1282 def guess_fontinfo (filename):
1283  fi = {
1284  'FontName': filename,
1285  'FamilyName': filename,
1286  'Weight': 'Regular',
1287  'ItalicAngle': 0,
1288  'DesignSize' : 12,
1289  'isFixedPitch' : 'false',
1290  'FullName': filename,
1291  }
1292 
1293  if re.search ('^cm', filename):
1294  fi.update (cm_guess_font_info (filename, fi))
1295  elif re.search ("^ec", filename):
1296  fi.update (ec_guess_font_info (filename, fi))
1297  elif options.read_afm:
1298  global afmfile
1299  if not afmfile:
1300  afmfile = find_file (filename + '.afm')
1301 
1302  if afmfile:
1303  afmfile = os.path.abspath (afmfile)
1304  afm_struct = afm.read_afm_file (afmfile)
1305  fi.update (afm_struct.__dict__)
1306  return fi
1307  else:
1308  sys.stderr.write ("Warning: no extra font information for this font.\n"
1309  + "Consider writing a XX_guess_font_info() routine.\n")
1310 
1311  return fi
1312 
1313 def do_file (filename):
1314  encoding_file = options.encoding_file
1315  global include_dirs
1316  include_dirs = options.include_dirs
1317  include_dirs.append (libdir)
1318  include_dirs.append (origdir)
1319 
1320  basename = strip_extension (filename, '.mf')
1321  progress (_ ("Font `%s'..." % basename))
1322  progress ('\n')
1323 
1324  ## setup encoding
1325  if encoding_file and not os.path.exists (encoding_file):
1326  encoding_file = find_file (encoding_file)
1327  elif encoding_file:
1328  encoding_file = os.path.abspath (encoding_file)
1329 
1330  ## setup TFM
1331  if options.tfm_file:
1332  options.tfm_file = os.path.abspath (options.tfm_file)
1333  else:
1334  tfm_try = find_file (basename + '.tfm')
1335  if tfm_try:
1336  options.tfm_file = tfm_try
1337 
1338 ## if "MFINPUTS" not in os.environ:
1339 ## os.environ["MFINPUTS"] = os.getcwd () + ";"
1340 
1341  ## must change dir before calling mktextfm.
1342  if options.keep_temp_dir:
1343  def nop():
1344  pass
1345  setup_temp (os.path.join (os.getcwd (), program_name + '.dir'))
1346  temp_dir.clean = nop
1347  else:
1348  setup_temp (None)
1349 
1350  if options.verbose:
1351  progress ('Temporary directory is `%s\'\n' % temp_dir)
1352 
1353  if not options.tfm_file:
1354  options.tfm_file = popen ("mktextfm %s 2>nul" % shell_escape_filename (basename)).read ()
1355  if options.tfm_file:
1356  options.tfm_file = options.tfm_file.strip ()
1357  options.tfm_file = os.path.abspath (options.tfm_file)
1358 
1359  if not options.tfm_file:
1360  error (_ ("Can not find a TFM file to match `%s'") % basename)
1361 
1362  metric = tfm.read_tfm_file (options.tfm_file)
1363 
1364  fontinfo = guess_fontinfo (basename)
1365  fontinfo.update (options.font_info)
1366 
1367  if not encoding_file:
1368  codingfile = 'tex256.enc'
1369  if metric.coding not in coding_dict:
1370  sys.stderr.write ("Unknown encoding `%s'; assuming tex256.\n" % metric.coding)
1371  else:
1372  codingfile = coding_dict[metric.coding]
1373 
1374  encoding_file = find_file (codingfile)
1375  if not encoding_file:
1376  error (_ ("can't find file `%s'" % codingfile))
1377 
1378  (enc_name, encoding) = read_encoding (encoding_file)
1379 
1380  if not len (options.glyphs):
1381  options.glyphs = list(range(0, len (encoding)))
1382 
1383  if not options.gffile:
1384  # run mf
1385  base = gen_pixel_font (basename, metric, options.magnification)
1386  options.gffile = base + 'gf'
1387  else:
1388  options.gffile = find_file (options.gffile)
1389 
1390  # the heart of the program:
1391  trace_font (basename, options.gffile, metric, options.glyphs, encoding,
1392  options.magnification, fontinfo)
1393 
1394  make_outputs (basename, options.formats, encoding)
1395  for format in options.formats:
1396  shutil.copy2 (basename + '.' + format, origdir)
1397 
1398  options.tfm_file = ''
1399  options.gffile = ''
1400  os.chdir (origdir)
1401 
1402 
1403 
1404 
1405 
1406 afmfile = ''
1407 backend_options = getenv ('MFTRACE_BACKEND_OPTIONS', '')
1408 def main ():
1409  global temp_dir
1410 
1411  files = parse_command_line ()
1412  identify (sys.stderr)
1413 
1414  for filename in files:
1415  do_file (filename)
1416  if temp_dir:
1417  del temp_dir
1418  sys.exit (exit_value)
1419 
1420 if __name__ =='__main__':
1421  main()
def __call__(self)
Definition: mftrace.py:127
def __str__(self)
Definition: mftrace.py:131
def __init__(self, name=None)
Definition: mftrace.py:111
def __del__(self)
Definition: mftrace.py:125
def __repr__(self)
Definition: mftrace.py:129
def cm_guess_font_info(filename, fontinfo)
Definition: mftrace.py:1137
def potrace_path_to_type1_ops(at_file, bitmap_metrics, tfm_wid, magnification)
Definition: mftrace.py:415
def do_file(filename)
Definition: mftrace.py:1313
def error(s)
Definition: mftrace.py:96
def shell_escape_filename(strng)
Definition: mftrace.py:70
def popen(cmd, mode='r', ignore_error=0)
Definition: mftrace.py:142
def to_type1(outlines, bbox, fontname, encoding, magnification, fontinfo)
Definition: mftrace.py:597
def autotrace_path_to_type1_ops(at_file, bitmap_metrics, tfm_wid, magnification)
Definition: mftrace.py:337
def potrace_command(fn, opts)
Definition: mftrace.py:246
def guess_fontinfo(filename)
Definition: mftrace.py:1282
def setup_temp(name)
Definition: mftrace.py:134
def gen_pixel_font(filename, metric, magnification)
Definition: mftrace.py:880
def zip_to_pairs(xs)
Definition: mftrace.py:323
def autotrace_command(fn, opts)
TRACING.
Definition: mftrace.py:241
def update_bbox_with_bbox(bb, dims)
Definition: mftrace.py:690
def flag_error()
Definition: mftrace.py:233
dictionary vars
Definition: mftrace.py:656
def make_pbm(filename, outname, char_number)
Definition: mftrace.py:297
def derive_font_name(family, fullname)
Definition: mftrace.py:1128
def warning(s)
Definition: mftrace.py:93
def trace_font(fontname, gf_file, metric, glyphs, encoding, magnification, fontinfo)
Definition: mftrace.py:522
def getenv(var, default)
Definition: mftrace.py:874
def unzip_pairs(tups)
Definition: mftrace.py:330
def nop()
if "MFINPUTS" not in os.environ: os.environ["MFINPUTS"] = os.getcwd () + ";"
Definition: mftrace.py:1343
def ec_guess_font_info(filename, fontinfo)
Definition: mftrace.py:1210
def find_file(nm)
Definition: mftrace.py:212
def system(cmd, ignore_error=0)
Definition: mftrace.py:150
def get_fontforge_command()
Definition: mftrace.py:708
def assemble_font(fontname, format, is_raw)
Definition: mftrace.py:793
def identify(port)
Definition: mftrace.py:74
def ps_encode_encoding(encoding)
Definition: mftrace.py:582
def interpolate(strng)
Definition: mftrace.py:32
def main()
Definition: mftrace.py:1408
def trace_one(pbmfile, id)
Definition: mftrace.py:255
def make_outputs(fontname, formats, encoding)
Definition: mftrace.py:812
def strip_extension(f, ext)
Definition: mftrace.py:172
def parse_command_line()
Definition: mftrace.py:943
def get_afm(t1_path, tfmname, encoding, out_path)
Definition: mftrace.py:767
def progress(s)
Definition: mftrace.py:90
def gen_unique_id(dict)
Definition: mftrace.py:593
def warranty()
Definition: mftrace.py:77
def update_bbox_with_point(bbox, pt)
Definition: mftrace.py:681
def tfm2kpx(tfmname, encoding)
Definition: mftrace.py:723
def get_binary(name)
Definition: mftrace.py:699
def read_encoding(file)
Definition: mftrace.py:306
def read_gf_dims(name, c)
Definition: mftrace.py:515
#define print(s)
Definition: pbmtoln03.c:48
@ range
Definition: preamble.c:52