Skip to content

Commit 7b00b1a

Browse files
committed
Clean up AFM code
Since AFM is now private, we can delete unused methods without deprecation. Additionally, add `AFM.get_glyph_name` so that the PostScript mathtext code doesn't need to special case AFM files.
1 parent 4f26d9a commit 7b00b1a

File tree

2 files changed

+44
-110
lines changed

2 files changed

+44
-110
lines changed

lib/matplotlib/_afm.py

Lines changed: 42 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""
2-
A python interface to Adobe Font Metrics Files.
2+
A Python interface to Adobe Font Metrics Files.
33
44
Although a number of other Python implementations exist, and may be more
55
complete than this, it was decided not to go with them because they were
@@ -16,19 +16,11 @@
1616
>>> from pathlib import Path
1717
>>> afm_path = Path(mpl.get_data_path(), 'fonts', 'afm', 'ptmr8a.afm')
1818
>>>
19-
>>> from matplotlib.afm import AFM
19+
>>> from matplotlib._afm import AFM
2020
>>> with afm_path.open('rb') as fh:
2121
... afm = AFM(fh)
22-
>>> afm.string_width_height('What the heck?')
23-
(6220.0, 694)
2422
>>> afm.get_fontname()
2523
'Times-Roman'
26-
>>> afm.get_kern_dist('A', 'f')
27-
0
28-
>>> afm.get_kern_dist('A', 'y')
29-
-92.0
30-
>>> afm.get_bbox_char('!')
31-
[130, -9, 238, 676]
3224
3325
As in the Adobe Font Metrics File Format Specification, all dimensions
3426
are given in units of 1/1000 of the scale factor (point size) of the font
@@ -87,20 +79,23 @@ def _to_bool(s):
8779

8880
def _parse_header(fh):
8981
"""
90-
Read the font metrics header (up to the char metrics) and returns
91-
a dictionary mapping *key* to *val*. *val* will be converted to the
92-
appropriate python type as necessary; e.g.:
82+
Read the font metrics header (up to the char metrics).
9383
94-
* 'False'->False
95-
* '0'->0
96-
* '-168 -218 1000 898'-> [-168, -218, 1000, 898]
84+
Returns
85+
-------
86+
dict
87+
A dictionary mapping *key* to *val*. Dictionary keys are:
9788
98-
Dictionary keys are
89+
StartFontMetrics, FontName, FullName, FamilyName, Weight, ItalicAngle,
90+
IsFixedPitch, FontBBox, UnderlinePosition, UnderlineThickness, Version,
91+
Notice, EncodingScheme, CapHeight, XHeight, Ascender, Descender,
92+
StartCharMetrics
9993
100-
StartFontMetrics, FontName, FullName, FamilyName, Weight,
101-
ItalicAngle, IsFixedPitch, FontBBox, UnderlinePosition,
102-
UnderlineThickness, Version, Notice, EncodingScheme, CapHeight,
103-
XHeight, Ascender, Descender, StartCharMetrics
94+
*val* will be converted to the appropriate Python type as necessary, e.g.,:
95+
96+
* 'False' -> False
97+
* '0' -> 0
98+
* '-168 -218 1000 898' -> [-168, -218, 1000, 898]
10499
"""
105100
header_converters = {
106101
b'StartFontMetrics': _to_float,
@@ -185,11 +180,9 @@ def _parse_header(fh):
185180

186181
def _parse_char_metrics(fh):
187182
"""
188-
Parse the given filehandle for character metrics information and return
189-
the information as dicts.
183+
Parse the given filehandle for character metrics information.
190184
191-
It is assumed that the file cursor is on the line behind
192-
'StartCharMetrics'.
185+
It is assumed that the file cursor is on the line behind 'StartCharMetrics'.
193186
194187
Returns
195188
-------
@@ -239,14 +232,15 @@ def _parse_char_metrics(fh):
239232

240233
def _parse_kern_pairs(fh):
241234
"""
242-
Return a kern pairs dictionary; keys are (*char1*, *char2*) tuples and
243-
values are the kern pair value. For example, a kern pairs line like
244-
``KPX A y -50``
245-
246-
will be represented as::
235+
Return a kern pairs dictionary.
247236
248-
d[ ('A', 'y') ] = -50
237+
Returns
238+
-------
239+
dict
240+
Keys are (*char1*, *char2*) tuples and values are the kern pair value. For
241+
example, a kern pairs line like ``KPX A y -50`` will be represented as::
249242
243+
d[ ('A', 'y') ] = -50
250244
"""
251245

252246
line = next(fh)
@@ -279,8 +273,7 @@ def _parse_kern_pairs(fh):
279273

280274
def _parse_composites(fh):
281275
"""
282-
Parse the given filehandle for composites information return them as a
283-
dict.
276+
Parse the given filehandle for composites information.
284277
285278
It is assumed that the file cursor is on the line behind 'StartComposites'.
286279
@@ -363,36 +356,6 @@ def __init__(self, fh):
363356
self._metrics, self._metrics_by_name = _parse_char_metrics(fh)
364357
self._kern, self._composite = _parse_optional(fh)
365358

366-
def get_bbox_char(self, c, isord=False):
367-
if not isord:
368-
c = ord(c)
369-
return self._metrics[c].bbox
370-
371-
def string_width_height(self, s):
372-
"""
373-
Return the string width (including kerning) and string height
374-
as a (*w*, *h*) tuple.
375-
"""
376-
if not len(s):
377-
return 0, 0
378-
total_width = 0
379-
namelast = None
380-
miny = 1e9
381-
maxy = 0
382-
for c in s:
383-
if c == '\n':
384-
continue
385-
wx, name, bbox = self._metrics[ord(c)]
386-
387-
total_width += wx + self._kern.get((namelast, name), 0)
388-
l, b, w, h = bbox
389-
miny = min(miny, b)
390-
maxy = max(maxy, b + h)
391-
392-
namelast = name
393-
394-
return total_width, maxy - miny
395-
396359
def get_str_bbox_and_descent(self, s):
397360
"""Return the string bounding box and the maximal descent."""
398361
if not len(s):
@@ -423,45 +386,33 @@ def get_str_bbox_and_descent(self, s):
423386

424387
return left, miny, total_width, maxy - miny, -miny
425388

426-
def get_str_bbox(self, s):
427-
"""Return the string bounding box."""
428-
return self.get_str_bbox_and_descent(s)[:4]
429-
430-
def get_name_char(self, c, isord=False):
431-
"""Get the name of the character, i.e., ';' is 'semicolon'."""
432-
if not isord:
433-
c = ord(c)
389+
def get_name_char(self, c):
390+
"""Get the name of the character code, i.e., ord(';') is 'semicolon'."""
434391
return self._metrics[c].name
435392

436-
def get_width_char(self, c, isord=False):
393+
def get_glyph_name(self, glyph_ind):
394+
"""Get the name of the glyph, i.e., ord(';') is 'semicolon'."""
395+
return self.get_name_char(glyph_ind)
396+
397+
def get_char_index(self, c):
437398
"""
438-
Get the width of the character from the character metric WX field.
399+
Return the glyph index corresponding to a character code point.
400+
401+
Note, for AFM fonts, we treat the glyph index the same as the codepoint.
439402
"""
440-
if not isord:
441-
c = ord(c)
403+
return c
404+
405+
def get_width_char(self, c):
406+
"""Get the width of the character code from the character metric WX field."""
442407
return self._metrics[c].width
443408

444409
def get_width_from_char_name(self, name):
445410
"""Get the width of the character from a type1 character name."""
446411
return self._metrics_by_name[name].width
447412

448-
def get_height_char(self, c, isord=False):
449-
"""Get the bounding box (ink) height of character *c* (space is 0)."""
450-
if not isord:
451-
c = ord(c)
452-
return self._metrics[c].bbox[-1]
453-
454-
def get_kern_dist(self, c1, c2):
455-
"""
456-
Return the kerning pair distance (possibly 0) for chars *c1* and *c2*.
457-
"""
458-
name1, name2 = self.get_name_char(c1), self.get_name_char(c2)
459-
return self.get_kern_dist_from_name(name1, name2)
460-
461413
def get_kern_dist_from_name(self, name1, name2):
462414
"""
463-
Return the kerning pair distance (possibly 0) for chars
464-
*name1* and *name2*.
415+
Return the kerning pair distance (possibly 0) for chars *name1* and *name2*.
465416
"""
466417
return self._kern.get((name1, name2), 0)
467418

@@ -493,7 +444,7 @@ def get_familyname(self):
493444
return re.sub(extras, '', name)
494445

495446
@property
496-
def family_name(self):
447+
def family_name(self): # For consistency with FT2Font.
497448
"""The font family name, e.g., 'Times'."""
498449
return self.get_familyname()
499450

@@ -516,17 +467,3 @@ def get_xheight(self):
516467
def get_underline_thickness(self):
517468
"""Return the underline thickness as float."""
518469
return self._header[b'UnderlineThickness']
519-
520-
def get_horizontal_stem_width(self):
521-
"""
522-
Return the standard horizontal stem width as float, or *None* if
523-
not specified in AFM file.
524-
"""
525-
return self._header.get(b'StdHW', None)
526-
527-
def get_vertical_stem_width(self):
528-
"""
529-
Return the standard vertical stem width as float, or *None* if
530-
not specified in AFM file.
531-
"""
532-
return self._header.get(b'StdVW', None)

lib/matplotlib/backends/backend_ps.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424

2525
import matplotlib as mpl
2626
from matplotlib import _api, cbook, _path, _text_helpers
27-
from matplotlib._afm import AFM
2827
from matplotlib.backend_bases import (
2928
_Backend, FigureCanvasBase, FigureManagerBase, RendererBase)
3029
from matplotlib.cbook import is_writable_file_like, file_requires_unicode
@@ -787,7 +786,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
787786
width = font.get_width_from_char_name(name)
788787
except KeyError:
789788
name = 'question'
790-
width = font.get_width_char('?')
789+
width = font.get_width_char(ord('?'))
791790
kern = font.get_kern_dist_from_name(last_name, name)
792791
last_name = name
793792
thisx += kern * scale
@@ -835,9 +834,7 @@ def draw_mathtext(self, gc, x, y, s, prop, angle):
835834
lastfont = font.postscript_name, fontsize
836835
self._pswriter.write(
837836
f"/{font.postscript_name} {fontsize} selectfont\n")
838-
glyph_name = (
839-
font.get_name_char(chr(num)) if isinstance(font, AFM) else
840-
font.get_glyph_name(font.get_char_index(num)))
837+
glyph_name = font.get_glyph_name(font.get_char_index(num))
841838
self._pswriter.write(
842839
f"{ox:g} {oy:g} moveto\n"
843840
f"/{glyph_name} glyphshow\n")

0 commit comments

Comments
 (0)