Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitd9bc2db

Browse files
committed
Improve usability of dviread.Text by third parties.
dviread.Text specifies individual glyphs in parsed dvi files; this isused by the pdf and svg backends (via textpath, for svg) to parse theresult of usetex-compiled strings and embed the right glyphs at theright places in the output file (as a reminder, agg currenly uses dvipngto rasterize the dvi file, and the ps backend relies on pstricks).Unfortunately, if third-party backends (e.g. mplcairo) want to do usethe same strategy as pdf/svg, then they need to jump through a few hoops(e.g. understand PsfontsMap and find_tex_font) and use some private APIs(_parse_enc), as explained below. Try to improve the situation, byadding some methods on the Text class (which may later allow deprecatingPsfontsMap and find_tex_font as public API).First, the actual font to be used is speficied via the `.font`attribute, which itself has a `.texname` which itself must be used asa key into `PsfontsMap(find_tex_font("pdftex.map"))` to get the actualfont path (and some other info). Instead, just provide a `.font_path`property. pdftex.map can also require that the font be "slanted" or"extended" (that's some of the "other info), lift that as well to`.font_effects`. The `.font` attribute has a `.size`; also we can liftup to `.font_size`. Altogether, this will allow making `.font` private(later) -- except for the fact that Text is a namedtuple so deprecatingfields is rather annoying.The trickiest part is actually specifying what glyph to select from thefont. dvi just gives us an integer, whose interpretation depends againon pdftex.map. If pdftex.map specifies "no encoding" for the font, thenthe integer is the "native glyph index" of the font, and should bepassed as-is to FreeType's FT_Load_Char (after selecting the nativecharmap). If pdftex.map does specify an encoding, then that's a filethat needs to be separately loaded, parsed (with _parse_enc), andultimately converts the index into a glyph name (which can be passed toFreeType's FT_Load_Glyph). Altogether, from the PoV of the end user,the "glyph specification" is thus either an int (a native charmap index)or a str (a glyph name); thus, provide `.glyph_spec` which is that API.As an example of using that API, see the changes to textpath.py.
1 parent3a994d2 commitd9bc2db

File tree

3 files changed

+91
-56
lines changed

3 files changed

+91
-56
lines changed

‎lib/matplotlib/dviread.py

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,70 @@
5858

5959
# The marks on a page consist of text and boxes. A page also has dimensions.
6060
Page=namedtuple('Page','text boxes height width descent')
61-
Text=namedtuple('Text','x y font glyph width')
6261
Box=namedtuple('Box','x y height width')
6362

6463

64+
# Also a namedtuple, for backcompat.
65+
classText(namedtuple('Text','x y font glyph width')):
66+
"""
67+
A glyph in the dvi file.
68+
69+
The *x* and *y* attributes directly position the glyph. The *font*,
70+
*glyph*, and *width* attributes are kept public for back-compatibility, but
71+
users wanting to draw the glyph themselves are encouraged to instead load
72+
the font specified by `font_path` at `font_size`, warp it with the effects
73+
specified by `font_effects`, and load the glyph specified by `glyph_spec`.
74+
"""
75+
76+
def_get_pdftexmap_entry(self):
77+
returnPsfontsMap(find_tex_file("pdftex.map"))[self.font.texname]
78+
79+
@property
80+
deffont_path(self):
81+
"""The `~pathlib.Path` to the font for this glyph."""
82+
psfont=self._get_pdftexmap_entry()
83+
ifpsfont.filenameisNone:
84+
raiseValueError("No usable font file found for {} ({}); "
85+
"the font may lack a Type-1 version"
86+
.format(psfont.psname.decode("ascii"),
87+
psfont.texname.decode("ascii")))
88+
returnPath(psfont.filename)
89+
90+
@property
91+
deffont_size(self):
92+
"""The font size."""
93+
returnself.font.size
94+
95+
@property
96+
deffont_effects(self):
97+
"""
98+
The "font effects" dict for this glyph.
99+
100+
This dict contains the values for this glyph of SlantFont and
101+
ExtendFont (if any), read off :file:`pdftex.map`.
102+
"""
103+
returnself._get_pdftexmap_entry().effects
104+
105+
@property
106+
defglyph_spec(self):
107+
"""
108+
Either the glyph name or the native charmap glyph index.
109+
110+
If :file:`pdftex.map` specifies an encoding for this glyph's font, that
111+
is a mapping of glyph indices to Adobe glyph names; use it to convert
112+
dvi indices to glyph names. Callers can then convert glyph names to
113+
glyph indices (with FT_Get_Name_Index/get_name_index), and load the
114+
glyph using FT_Load_Glyph/load_glyph.
115+
116+
If :file:`pdftex.map` specifies no encoding, the indices directly map
117+
to the font's "native" charmap; glyphs should directly loaded using
118+
FT_Load_Char/load_char after selecting the native charmap.
119+
"""
120+
entry=self._get_pdftexmap_entry()
121+
return (_parse_enc(entry.encoding)[self.glyph]
122+
ifentry.encodingisnotNoneelseself.glyph)
123+
124+
65125
# Opcode argument parsing
66126
#
67127
# Each of the following functions takes a Dvi object and delta,

‎lib/matplotlib/tests/test_usetex.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ def test_missing_psfont(fmt, monkeypatch):
131131
monkeypatch.setattr(
132132
dviread.PsfontsMap,'__getitem__',
133133
lambdaself,k:dviread.PsFont(
134-
texname='texfont',psname='Some Font',
134+
texname=b'texfont',psname=b'Some Font',
135135
effects=None,encoding=None,filename=None))
136136
mpl.rcParams['text.usetex']=True
137137
fig,ax=plt.subplots()

‎lib/matplotlib/textpath.py

Lines changed: 29 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
fromcollectionsimportOrderedDict
2-
importfunctools
32
importlogging
43
importurllib.parse
54

@@ -243,25 +242,28 @@ def get_glyphs_tex(self, prop, s, glyph_map=None,
243242

244243
# Gather font information and do some setup for combining
245244
# characters into strings.
246-
forx1,y1,dvifont,glyph,widthinpage.text:
247-
font,enc=self._get_ps_font_and_encoding(dvifont.texname)
248-
char_id=self._get_char_id(font,glyph)
249-
245+
fortextinpage.text:
246+
font=get_font(text.font_path)
247+
char_id=self._get_char_id(font,text.glyph)
250248
ifchar_idnotinglyph_map:
249+
spec=text.glyph_spec
251250
font.clear()
252251
font.set_size(self.FONT_SCALE,self.DPI)
253-
# See comments in_get_ps_font_and_encoding.
254-
ifencisnotNone:
255-
index=font.get_name_index(enc[glyph])
252+
# See comments inText.get_glyph_spec.
253+
ifisinstance(spec,str):
254+
index=font.get_name_index(spec)
256255
font.load_glyph(index,flags=LOAD_TARGET_LIGHT)
257-
else:
258-
font.load_char(glyph,flags=LOAD_TARGET_LIGHT)
256+
elifisinstance(spec,int):
257+
self._select_native_charmap(font)
258+
font.load_char(spec,flags=LOAD_TARGET_LIGHT)
259+
else:# Should not occur.
260+
raiseTypeError("Unexpected glyph spec type")
259261
glyph_map_new[char_id]=font.get_path()
260262

261263
glyph_ids.append(char_id)
262-
xpositions.append(x1)
263-
ypositions.append(y1)
264-
sizes.append(dvifont.size/self.FONT_SCALE)
264+
xpositions.append(text.x)
265+
ypositions.append(text.y)
266+
sizes.append(text.font_size/self.FONT_SCALE)
265267

266268
myrects= []
267269

@@ -277,48 +279,21 @@ def get_glyphs_tex(self, prop, s, glyph_map=None,
277279
glyph_map_new,myrects)
278280

279281
@staticmethod
280-
@functools.lru_cache(50)
281-
def_get_ps_font_and_encoding(texname):
282-
tex_font_map=dviread.PsfontsMap(dviread._find_tex_file('pdftex.map'))
283-
psfont=tex_font_map[texname]
284-
ifpsfont.filenameisNone:
285-
raiseValueError(
286-
f"No usable font file found for{psfont.psname} ({texname}). "
287-
f"The font may lack a Type-1 version.")
288-
289-
font=get_font(psfont.filename)
290-
291-
ifpsfont.encoding:
292-
# If psfonts.map specifies an encoding, use it: it gives us a
293-
# mapping of glyph indices to Adobe glyph names; use it to convert
294-
# dvi indices to glyph names and use the FreeType-synthesized
295-
# Unicode charmap to convert glyph names to glyph indices (with
296-
# FT_Get_Name_Index/get_name_index), and load the glyph using
297-
# FT_Load_Glyph/load_glyph. (That charmap has a coverage at least
298-
# as good as, and possibly better than, the native charmaps.)
299-
enc=dviread._parse_enc(psfont.encoding)
300-
else:
301-
# If psfonts.map specifies no encoding, the indices directly
302-
# map to the font's "native" charmap; so don't use the
303-
# FreeType-synthesized charmap but the native ones (we can't
304-
# directly identify it but it's typically an Adobe charmap), and
305-
# directly load the dvi glyph indices using FT_Load_Char/load_char.
306-
forcharmap_codein [
307-
1094992451,# ADOBE_CUSTOM.
308-
1094995778,# ADOBE_STANDARD.
309-
]:
310-
try:
311-
font.select_charmap(charmap_code)
312-
except (ValueError,RuntimeError):
313-
pass
314-
else:
315-
break
282+
def_select_native_charmap(font):
283+
# Select the native charmap. (we can't directly identify it but it's
284+
# typically an Adobe charmap).
285+
forcharmap_codein [
286+
1094992451,# ADOBE_CUSTOM.
287+
1094995778,# ADOBE_STANDARD.
288+
]:
289+
try:
290+
font.select_charmap(charmap_code)
291+
except (ValueError,RuntimeError):
292+
pass
316293
else:
317-
_log.warning("No supported encoding in font (%s).",
318-
psfont.filename)
319-
enc=None
320-
321-
returnfont,enc
294+
break
295+
else:
296+
_log.warning("No supported encoding in font (%s).",font.fname)
322297

323298

324299
text_to_path=TextToPath()

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp