Source code for PyDvi.Font.FontMap

####################################################################################################
# 
# PyDvi - A Python Library to Process DVI Stream
# Copyright (C) 2014 Fabrice Salvaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
# 
####################################################################################################

####################################################################################################
#
# Audit
#
# - 01/11/2011 Fabrice
#   - check init definition
#
####################################################################################################

"""This module handles font map files.

A font map file gives the correspondance between the TeX PK fonts and their PostScript
equivalents. These files use the ``.map`` extension.

For example, the file :file:`pdftex.map` contains lines like this one::

  futbo8r Utopia-Bold ".167 SlantFont TeXBase1Encoding ReEncodeFont" <8r.enc <putb8a.pfb

Each line describes a PK font using the following format::

  PK_FONT_NAME PS_FONT_NAME "PostScript snippet" <FILE_NAME1 <FILE_NAME2

The first word is the TeX font name and the second word is the PostScript font name. The PostScript
font name can be omitted if it is the same than for TeX. The word starting by "<" are filenames to
be included in the PostScript file. A filename with the extension ``.enc`` is an encoding file and a
filename with the extension ``.pfb`` is a Printer Font Binary file. The text enclosed by double
quotes is optional and gives a PostScript snippet to be inserted in the PostScript file. It can be
placed at the end of the line.

The percent character is used for comment as for TeX.

.. What is the source of this:
.. one or two '<'
.. This can be overridden with a left bracket: '<[encfile' indicates an encoding file named encfile.

References:

* The Font Installation Guide Using Postscript fonts to their full potential with Latex. Originally
  written by Philipp Lehman. December 2004. Revision 2.14. cf. Creating map files Part.
  http://www.ctan.org/tex-archive/info/Type1fonts/fontinstallationguide
* updmap(1) - Update font map files for TeX output drivers.
* updmap.cfg(5) - Configuration of font mapping/inclusion for dvips and friends

To parse the font map :file:`pdftex.map` do::

  font_map = FontMap('/usr/share/texmf/fonts/map/pdftex/updmap/pdftex.map')

Each entry is stored in a :class:`FontMapEntry` instance and can be retrieved using its TeX name as
key::

  font_map_entry = font_map['futbo8r']

The ``.pfb`` file name and the other parameters are stored as attributes::

  >>> font_map_entry.pfb_filename
  'putb8a.pfb'

"""

####################################################################################################

__all__ = ['FontMap', 'FontMapEntry']

####################################################################################################

import os

####################################################################################################

from ..Tools.Logging import print_card
from ..Tools.TexCommentedFile import TexCommentedFile

####################################################################################################

[docs]class FontMapEntry(object): """ This class encapsulates a font map entry. Public attributes: :attr:`tex_name` :attr:`ps_font_name` :attr:`ps_snippet` :attr:`effects` :attr:`encoding` :attr:`pfb_filename` """ ############################################## def __init__(self, tex_name, ps_font_name, ps_snippet, effects, encoding, pfb_filename): self.tex_name = tex_name self.ps_font_name = ps_font_name self.ps_snippet = ps_snippet self.effects = effects self.encoding = encoding self.pfb_filename = pfb_filename ##############################################
[docs] def print_summary(self): message_pattern = '''Font Map Entry %s - PS font name %s - ps snippet "%s" - effects %s - encoding %s - pfb_filename %s''' message = message_pattern % ( self.tex_name, self.ps_font_name, self.ps_snippet, self.effects, self.encoding, self.pfb_filename, ) print_card(message)
####################################################################################################
[docs]class FontMap(object): """ This class parses a font map file. """ ############################################## def __init__(self, filename): self.name = os.path.basename(filename).replace('.map', '') self._map = {} # try: with TexCommentedFile(filename) as font_map_file: for line in font_map_file: try: self._parse_line(line) except: pass # except: # raise NameError('Bad fontmap file') ############################################## def __getitem__(self, tex_name): return self._map[tex_name] ##############################################
[docs] def _register_entry(self, font_map_entry): """ Register a font map entry. """ self._map[font_map_entry.tex_name] = font_map_entry
##############################################
[docs] def _parse_line(self, line): """ Parse a line. """ # 1) Extract PostScript Snippet if there first_double_quote_index = line.find('"') if first_double_quote_index != -1: last_double_quote_index = line.find('"', first_double_quote_index+1) ps_snippet = line[first_double_quote_index+1:last_double_quote_index] effects = FontMap._parse_effects(ps_snippet) line = line[:first_double_quote_index] + line[last_double_quote_index+1:] else: ps_snippet = '' effects = {} # Fixme: # pigpen <<pigpen.pfa sub_strings = [x.strip() for x in line.split('<')] if len(sub_strings) == 1: raise ValueError("Font map entry has any <FileNAME") right_part, filenames = sub_strings[0], sub_strings[1:] font_names = right_part.split() if len(font_names) == 2: tex_name, ps_font_name = font_names else: tex_name = ps_font_name = font_names[0] encoding_filename, pfb_filename = None, None for filename in filenames: if filename.startswith('['): assert encoding_filename is None encoding_filename = filename[1:] elif filename.endswith('.enc'): assert encoding_filename is None encoding_filename = filename elif filename.endswith('.pfb') or filename.endswith('.pfa') or filename.endswith('.ttf'): assert pfb_filename is None pfb_filename = filename else: raise ValueError("Unknown file extension for file %s" % (filename)) font_map_entry = FontMapEntry(tex_name, ps_font_name, ps_snippet, effects, encoding_filename, pfb_filename) self._register_entry(font_map_entry)
############################################## @staticmethod
[docs] def _parse_effects(ps_snippet): """ Parse the PostScript snippet. """ effects_list = ps_snippet.split() effects = {} for key_word in 'SlantFont', 'ExtendFont': try: # parameter is followed by the command parameter_index = effects_list.index(key_word) -1 effects[key_word] = float(effects_list[parameter_index]) except ValueError: # key word was not found pass return effects
##############################################
[docs] def print_summary(self): print_card('Font Map %s' % (self.name)) for font_map_entry in self._map.values(): font_map_entry.print_summary()
#################################################################################################### # # End # ####################################################################################################