From 94cb1759f79585b6d9b36aae6959f08f7fd7c7c1 Mon Sep 17 00:00:00 2001 From: Simon Cozens Date: Tue, 12 May 2020 11:18:36 +0100 Subject: [PATCH] [docs] Document afmLib (#1933) --- Doc/source/afmLib.rst | 10 +++--- Lib/fontTools/afmLib.py | 73 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 74 insertions(+), 9 deletions(-) diff --git a/Doc/source/afmLib.rst b/Doc/source/afmLib.rst index b9c419fe0..ab9f35678 100644 --- a/Doc/source/afmLib.rst +++ b/Doc/source/afmLib.rst @@ -1,8 +1,8 @@ -###### -afmLib -###### +########################################### +afmLib: Read/write Adobe Font Metrics files +########################################### .. automodule:: fontTools.afmLib - :inherited-members: + +.. autoclass:: fontTools.afmLib.AFM :members: - :undoc-members: diff --git a/Lib/fontTools/afmLib.py b/Lib/fontTools/afmLib.py index 9b0c9e4fc..7983fa09b 100644 --- a/Lib/fontTools/afmLib.py +++ b/Lib/fontTools/afmLib.py @@ -1,8 +1,50 @@ -"""Module for reading and writing AFM files.""" +"""Module for reading and writing AFM (Adobe Font Metrics) files. + +Note that this has been designed to read in AFM files generated by Fontographer +and has not been tested on many other files. In particular, it does not +implement the whole Adobe AFM specification [#f1]_ but, it should read most +"common" AFM files. + +Here is an example of using `afmLib` to read, modify and write an AFM file: + + >>> from fontTools.afmLib import AFM + >>> f = AFM("Tests/afmLib/data/TestAFM.afm") + >>> + >>> # Accessing a pair gets you the kern value + >>> f[("V","A")] + -60 + >>> + >>> # Accessing a glyph name gets you metrics + >>> f["A"] + (65, 668, (8, -25, 660, 666)) + >>> # (charnum, width, bounding box) + >>> + >>> # Accessing an attribute gets you metadata + >>> f.FontName + 'TestFont-Regular' + >>> f.FamilyName + 'TestFont' + >>> f.Weight + 'Regular' + >>> f.XHeight + 500 + >>> f.Ascender + 750 + >>> + >>> # Attributes and items can also be set + >>> f[("A","V")] = -150 # Tighten kerning + >>> f.FontName = "TestFont Squished" + >>> + >>> # And the font written out again + >>> f.write("testfont-squished.afm") + +.. rubric:: Footnotes + +.. [#f1] `Adobe Technote 5004 `_, + Adobe Font Metrics File Format Specification. + +""" -# XXX reads AFM's generated by Fog, not tested with much else. -# It does not implement the full spec (Adobe Technote 5004, Adobe Font Metrics -# File Format Specification). Still, it should read most "common" AFM files. from fontTools.misc.py23 import * import re @@ -97,6 +139,11 @@ class AFM(object): ] def __init__(self, path=None): + """AFM file reader. + + Instantiating an object with a path name will cause the file to be opened, + read, and parsed. Alternatively the path can be left unspecified, and a + file can be parsed later with the :meth:`read` method.""" self._attrs = {} self._chars = {} self._kerning = {} @@ -107,6 +154,7 @@ class AFM(object): self.read(path) def read(self, path): + """Opens, reads and parses a file.""" lines = readlines(path) for line in lines: if not line.strip(): @@ -189,6 +237,7 @@ class AFM(object): self._composites[charname] = components def write(self, path, sep='\r'): + """Writes out an AFM font to the given path.""" import time lines = [ "StartFontMetrics 2.0", "Comment Generated by afmLib; at %s" % ( @@ -258,24 +307,40 @@ class AFM(object): writelines(path, lines, sep) def has_kernpair(self, pair): + """Returns `True` if the given glyph pair (specified as a tuple) exists + in the kerning dictionary.""" return pair in self._kerning def kernpairs(self): + """Returns a list of all kern pairs in the kerning dictionary.""" return list(self._kerning.keys()) def has_char(self, char): + """Returns `True` if the given glyph exists in the font.""" return char in self._chars def chars(self): + """Returns a list of all glyph names in the font.""" return list(self._chars.keys()) def comments(self): + """Returns all comments from the file.""" return self._comments def addComment(self, comment): + """Adds a new comment to the file.""" self._comments.append(comment) def addComposite(self, glyphName, components): + """Specifies that the glyph `glyphName` is made up of the given components. + The components list should be of the following form:: + + [ + (glyphname, xOffset, yOffset), + ... + ] + + """ self._composites[glyphName] = components def __getattr__(self, attr):