ai-content-maker/.venv/Lib/site-packages/matplotlib/backends/_backend_pdf_ps.py

146 lines
4.3 KiB
Python

"""
Common functionality between the PDF and PS backends.
"""
from io import BytesIO
import functools
from fontTools import subset
import matplotlib as mpl
from .. import font_manager, ft2font
from .._afm import AFM
from ..backend_bases import RendererBase
@functools.lru_cache(50)
def _cached_get_afm_from_fname(fname):
with open(fname, "rb") as fh:
return AFM(fh)
def get_glyphs_subset(fontfile, characters):
"""
Subset a TTF font
Reads the named fontfile and restricts the font to the characters.
Returns a serialization of the subset font as file-like object.
Parameters
----------
fontfile : str
Path to the font file
characters : str
Continuous set of characters to include in subset
"""
options = subset.Options(glyph_names=True, recommended_glyphs=True)
# Prevent subsetting extra tables.
options.drop_tables += [
'FFTM', # FontForge Timestamp.
'PfEd', # FontForge personal table.
'BDF', # X11 BDF header.
'meta', # Metadata stores design/supported languages (meaningless for subsets).
]
# if fontfile is a ttc, specify font number
if fontfile.endswith(".ttc"):
options.font_number = 0
with subset.load_font(fontfile, options) as font:
subsetter = subset.Subsetter(options=options)
subsetter.populate(text=characters)
subsetter.subset(font)
fh = BytesIO()
font.save(fh, reorderTables=False)
return fh
class CharacterTracker:
"""
Helper for font subsetting by the pdf and ps backends.
Maintains a mapping of font paths to the set of character codepoints that
are being used from that font.
"""
def __init__(self):
self.used = {}
def track(self, font, s):
"""Record that string *s* is being typeset using font *font*."""
char_to_font = font._get_fontmap(s)
for _c, _f in char_to_font.items():
self.used.setdefault(_f.fname, set()).add(ord(_c))
def track_glyph(self, font, glyph):
"""Record that codepoint *glyph* is being typeset using font *font*."""
self.used.setdefault(font.fname, set()).add(glyph)
class RendererPDFPSBase(RendererBase):
# The following attributes must be defined by the subclasses:
# - _afm_font_dir
# - _use_afm_rc_name
def __init__(self, width, height):
super().__init__()
self.width = width
self.height = height
def flipy(self):
# docstring inherited
return False # y increases from bottom to top.
def option_scale_image(self):
# docstring inherited
return True # PDF and PS support arbitrary image scaling.
def option_image_nocomposite(self):
# docstring inherited
# Decide whether to composite image based on rcParam value.
return not mpl.rcParams["image.composite_image"]
def get_canvas_width_height(self):
# docstring inherited
return self.width * 72.0, self.height * 72.0
def get_text_width_height_descent(self, s, prop, ismath):
# docstring inherited
if ismath == "TeX":
return super().get_text_width_height_descent(s, prop, ismath)
elif ismath:
parse = self._text2path.mathtext_parser.parse(s, 72, prop)
return parse.width, parse.height, parse.depth
elif mpl.rcParams[self._use_afm_rc_name]:
font = self._get_font_afm(prop)
l, b, w, h, d = font.get_str_bbox_and_descent(s)
scale = prop.get_size_in_points() / 1000
w *= scale
h *= scale
d *= scale
return w, h, d
else:
font = self._get_font_ttf(prop)
font.set_text(s, 0.0, flags=ft2font.LOAD_NO_HINTING)
w, h = font.get_width_height()
d = font.get_descent()
scale = 1 / 64
w *= scale
h *= scale
d *= scale
return w, h, d
def _get_font_afm(self, prop):
fname = font_manager.findfont(
prop, fontext="afm", directory=self._afm_font_dir)
return _cached_get_afm_from_fname(fname)
def _get_font_ttf(self, prop):
fnames = font_manager.fontManager._find_fonts_by_props(prop)
font = font_manager.get_font(fnames)
font.clear()
font.set_size(prop.get_size_in_points(), 72)
return font