Skip to content

Commit 2cf627b

Browse files
committed
pdf/ps: Support any font in a collection
1 parent ba80e42 commit 2cf627b

File tree

11 files changed

+3071
-30
lines changed

11 files changed

+3071
-30
lines changed

lib/matplotlib/backends/_backend_pdf_ps.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def get_glyphs_subset(fontfile, characters):
2828
2929
Parameters
3030
----------
31-
fontfile : str
31+
fontfile : FontPath
3232
Path to the font file
3333
characters : str
3434
Continuous set of characters to include in subset
@@ -66,8 +66,7 @@ def get_glyphs_subset(fontfile, characters):
6666
'xref', # The cross-reference table (some Apple font tooling information).
6767
]
6868
# if fontfile is a ttc, specify font number
69-
if fontfile.endswith(".ttc"):
70-
options.font_number = 0
69+
options.font_number = fontfile.face_index
7170

7271
font = subset.load_font(fontfile, options)
7372
subsetter = subset.Subsetter(options=options)
@@ -110,11 +109,13 @@ def track(self, font, s):
110109
"""Record that string *s* is being typeset using font *font*."""
111110
char_to_font = font._get_fontmap(s)
112111
for _c, _f in char_to_font.items():
113-
self.used.setdefault(_f.fname, set()).add(ord(_c))
112+
font_path = font_manager.FontPath(_f.fname, _f.face_index)
113+
self.used.setdefault(font_path, set()).add(ord(_c))
114114

115115
def track_glyph(self, font, glyph):
116116
"""Record that codepoint *glyph* is being typeset using font *font*."""
117-
self.used.setdefault(font.fname, set()).add(glyph)
117+
font_path = font_manager.FontPath(font.fname, font.face_index)
118+
self.used.setdefault(font_path, set()).add(glyph)
118119

119120

120121
class RendererPDFPSBase(RendererBase):

lib/matplotlib/backends/backend_pdf.py

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
RendererBase)
3434
from matplotlib.backends.backend_mixed import MixedModeRenderer
3535
from matplotlib.figure import Figure
36-
from matplotlib.font_manager import get_font, fontManager as _fontManager
36+
from matplotlib.font_manager import FontPath, get_font, fontManager as _fontManager
3737
from matplotlib._afm import AFM
3838
from matplotlib.ft2font import FT2Font, FaceFlags, Kerning, LoadFlags, StyleFlags
3939
from matplotlib.transforms import Affine2D, BboxBase
@@ -910,8 +910,10 @@ def fontName(self, fontprop):
910910
as the filename of the font.
911911
"""
912912

913-
if isinstance(fontprop, str):
913+
if isinstance(fontprop, FontPath):
914914
filenames = [fontprop]
915+
elif isinstance(fontprop, str):
916+
filenames = [FontPath(fontprop, 0)]
915917
elif mpl.rcParams['pdf.use14corefonts']:
916918
filenames = _fontManager._find_fonts_by_props(
917919
fontprop, fontext='afm', directory=RendererPdf._afm_font_dir
@@ -950,9 +952,8 @@ def writeFonts(self):
950952
for pdfname, dvifont in sorted(self._dviFontInfo.items()):
951953
_log.debug('Embedding Type-1 font %s from dvi.', dvifont.texname)
952954
fonts[pdfname] = self._embedTeXFont(dvifont)
953-
for filename in sorted(self._fontNames):
954-
Fx = self._fontNames[filename]
955-
_log.debug('Embedding font %s.', filename)
955+
for filename, Fx in sorted(self._fontNames.items()):
956+
_log.debug('Embedding font %r.', filename)
956957
if filename.endswith('.afm'):
957958
# from pdf.use14corefonts
958959
_log.debug('Writing AFM font.')
@@ -1004,7 +1005,8 @@ def _embedTeXFont(self, dvifont):
10041005

10051006
# Reduce the font to only the glyphs used in the document, get the encoding
10061007
# for that subset, and compute various properties based on the encoding.
1007-
chars = frozenset(self._character_tracker.used[dvifont.fname])
1008+
font_path = FontPath(dvifont.fname, dvifont.face_index)
1009+
chars = frozenset(self._character_tracker.used[font_path])
10081010
t1font = t1font.subset(chars, self._get_subset_prefix(chars))
10091011
fontdict['BaseFont'] = Name(t1font.prop['FontName'])
10101012
# createType1Descriptor writes the font data as a side effect
@@ -1113,6 +1115,7 @@ def _get_xobject_glyph_name(self, filename, glyph_name):
11131115
return "-".join([
11141116
Fx.name.decode(),
11151117
os.path.splitext(os.path.basename(filename))[0],
1118+
str(filename.face_index),
11161119
glyph_name])
11171120

11181121
_identityToUnicodeCMap = b"""/CIDInit /ProcSet findresource begin
@@ -1270,11 +1273,11 @@ def embedTTFType42(font, characters, descriptor):
12701273
toUnicodeMapObject = self.reserveObject('ToUnicode map')
12711274

12721275
subset_str = "".join(chr(c) for c in characters)
1273-
_log.debug("SUBSET %s characters: %s", filename, subset_str)
1276+
_log.debug("SUBSET %r characters: %s", filename, subset_str)
12741277
with _backend_pdf_ps.get_glyphs_subset(filename, subset_str) as subset:
12751278
fontdata = _backend_pdf_ps.font_as_file(subset)
12761279
_log.debug(
1277-
"SUBSET %s %d -> %d", filename,
1280+
"SUBSET %r %d -> %d", filename,
12781281
os.stat(filename).st_size, fontdata.getbuffer().nbytes
12791282
)
12801283

@@ -2218,18 +2221,18 @@ def draw_mathtext(self, gc, x, y, s, prop, angle):
22182221
self.file.output(Op.begin_text)
22192222
for font, fontsize, num, ox, oy in glyphs:
22202223
self.file._character_tracker.track_glyph(font, num)
2221-
fontname = font.fname
2224+
font_path = FontPath(font.fname, font.face_index)
22222225
if not _font_supports_glyph(fonttype, num):
22232226
# Unsupported chars (i.e. multibyte in Type 3 or beyond BMP in
22242227
# Type 42) must be emitted separately (below).
22252228
unsupported_chars.append((font, fontsize, ox, oy, num))
22262229
else:
22272230
self._setup_textpos(ox, oy, 0, oldx, oldy)
22282231
oldx, oldy = ox, oy
2229-
if (fontname, fontsize) != prev_font:
2230-
self.file.output(self.file.fontName(fontname), fontsize,
2232+
if (font_path, fontsize) != prev_font:
2233+
self.file.output(self.file.fontName(font_path), fontsize,
22312234
Op.selectfont)
2232-
prev_font = fontname, fontsize
2235+
prev_font = font_path, fontsize
22332236
self.file.output(self.encode_string(chr(num), fonttype),
22342237
Op.show)
22352238
self.file.output(Op.end_text)
@@ -2413,7 +2416,8 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
24132416
self.file.output(Op.begin_text)
24142417
prev_start_x = 0
24152418
for ft_object, start_x, kerns_or_chars in singlebyte_chunks:
2416-
ft_name = self.file.fontName(ft_object.fname)
2419+
font_path = FontPath(ft_object.fname, ft_object.face_index)
2420+
ft_name = self.file.fontName(font_path)
24172421
self.file.output(ft_name, fontsize, Op.selectfont)
24182422
self._setup_textpos(start_x, 0, 0, prev_start_x, 0, 0)
24192423
self.file.output(
@@ -2435,7 +2439,8 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
24352439
def _draw_xobject_glyph(self, font, fontsize, glyph_idx, x, y):
24362440
"""Draw a multibyte character from a Type 3 font as an XObject."""
24372441
glyph_name = font.get_glyph_name(glyph_idx)
2438-
name = self.file._get_xobject_glyph_name(font.fname, glyph_name)
2442+
name = self.file._get_xobject_glyph_name(FontPath(font.fname, font.face_index),
2443+
glyph_name)
24392444
self.file.output(
24402445
Op.gsave,
24412446
0.001 * fontsize, 0, 0, 0.001 * fontsize, x, y, Op.concat_matrix,

lib/matplotlib/backends/backend_ps.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ def _font_to_ps_type3(font_path, chars):
9494
9595
Parameters
9696
----------
97-
font_path : path-like
97+
font_path : FontPath
9898
Path to the font to be subsetted.
9999
chars : str
100100
The characters to include in the subsetted font.
@@ -175,22 +175,18 @@ def _font_to_ps_type42(font_path, chars, fh):
175175
176176
Parameters
177177
----------
178-
font_path : path-like
178+
font_path : FontPath
179179
Path to the font to be subsetted.
180180
chars : str
181181
The characters to include in the subsetted font.
182182
fh : file-like
183183
Where to write the font.
184184
"""
185185
subset_str = ''.join(chr(c) for c in chars)
186-
_log.debug("SUBSET %s characters: %s", font_path, subset_str)
186+
_log.debug("SUBSET %r characters: %s", font_path, subset_str)
187187
try:
188-
kw = {}
189-
# fix this once we support loading more fonts from a collection
190-
# https://github.com/matplotlib/matplotlib/issues/3135#issuecomment-571085541
191-
if font_path.endswith('.ttc'):
192-
kw['fontNumber'] = 0
193-
with (fontTools.ttLib.TTFont(font_path, **kw) as font,
188+
with (fontTools.ttLib.TTFont(font_path.path,
189+
fontNumber=font_path.face_index) as font,
194190
_backend_pdf_ps.get_glyphs_subset(font_path, subset_str) as subset):
195191
fontdata = _backend_pdf_ps.font_as_file(subset).getvalue()
196192
_log.debug(

lib/matplotlib/dviread.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,10 @@ def fname(self):
610610
"""A fake filename"""
611611
return self.texname.decode('latin-1')
612612

613+
@property
614+
def face_index(self): # For compatibility with FT2Font.
615+
return 0
616+
613617
def _get_fontmap(self, string):
614618
"""Get the mapping from characters to the font that includes them.
615619

lib/matplotlib/dviread.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ class DviFont:
6868
def widths(self) -> list[int]: ...
6969
@property
7070
def fname(self) -> str: ...
71+
@property
72+
def face_index(self) -> int: ...
7173

7274
class Vf(Dvi):
7375
def __init__(self, filename: str | os.PathLike) -> None: ...
Binary file not shown.
Binary file not shown.

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy