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

Commita2277af

Browse files
authored
Merge pull request#12928 from anntzer/textpath-encoding
FIX: textpath encoding
2 parents7a3456c +722de6f commita2277af

File tree

3 files changed

+104
-63
lines changed

3 files changed

+104
-63
lines changed

‎lib/matplotlib/dviread.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -968,10 +968,41 @@ def _parse(file):
968968
raiseValueError("Cannot locate end of encoding in {}"
969969
.format(file))
970970
data=data[:end]
971-
972971
returnre.findall(br'/([^][{}<>\s]+)',data)
973972

974973

974+
# Note: this function should ultimately replace the Encoding class, which
975+
# appears to be mostly broken: because it uses b''.join(), there is no
976+
# whitespace left between glyph names (only slashes) so the final re.findall
977+
# returns a single string with all glyph names. However this does not appear
978+
# to bother backend_pdf, so that needs to be investigated more. (The fixed
979+
# version below is necessary for textpath/backend_svg, though.)
980+
def_parse_enc(path):
981+
r"""
982+
Parses a \*.enc file referenced from a psfonts.map style file.
983+
The format this class understands is a very limited subset of PostScript.
984+
985+
Parameters
986+
----------
987+
path : os.PathLike
988+
989+
Returns
990+
-------
991+
encoding : list
992+
The nth entry of the list is the PostScript glyph name of the nth
993+
glyph.
994+
"""
995+
withopen(path,encoding="ascii")asfile:
996+
no_comments="\n".join(line.split("%")[0].rstrip()forlineinfile)
997+
array=re.search(r"(?s)\[(.*)\]",no_comments).group(1)
998+
lines= [lineforlineinarray.split("\n")ifline]
999+
ifall(line.startswith("/")forlineinlines):
1000+
return [line[1:]forlineinlines]
1001+
else:
1002+
raiseValueError(
1003+
"Failed to parse {} as Postscript encoding".format(path))
1004+
1005+
9751006
@lru_cache()
9761007
deffind_tex_file(filename,format=None):
9771008
"""

‎lib/matplotlib/tests/test_backend_svg.py

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
11
importnumpyasnp
22
fromioimportBytesIO
33
importos
4+
importre
45
importtempfile
56
importwarnings
67
importxml.parsers.expat
78

89
importpytest
910

11+
importmatplotlibasmpl
12+
frommatplotlibimportdviread
13+
frommatplotlib.figureimportFigure
1014
importmatplotlib.pyplotasplt
1115
frommatplotlib.testing.decoratorsimportimage_comparison
12-
importmatplotlib
13-
frommatplotlibimportdviread
1416

1517

1618
withwarnings.catch_warnings():
1719
warnings.simplefilter('ignore')
1820
needs_usetex=pytest.mark.skipif(
19-
notmatplotlib.checkdep_usetex(True),
21+
notmpl.checkdep_usetex(True),
2022
reason="This test needs a TeX installation")
2123

2224

@@ -107,15 +109,10 @@ def test_bold_font_output_with_none_fonttype():
107109

108110
def_test_determinism_save(filename,usetex):
109111
# This function is mostly copy&paste from "def test_visibility"
110-
# To require no GUI, we use Figure and FigureCanvasSVG
111-
# instead of plt.figure and fig.savefig
112-
frommatplotlib.figureimportFigure
113-
frommatplotlib.backends.backend_svgimportFigureCanvasSVG
114-
frommatplotlibimportrc
115-
rc('svg',hashsalt='asdf')
116-
rc('text',usetex=usetex)
112+
mpl.rc('svg',hashsalt='asdf')
113+
mpl.rc('text',usetex=usetex)
117114

118-
fig=Figure()
115+
fig=Figure()# Require no GUI.
119116
ax=fig.add_subplot(111)
120117

121118
x=np.linspace(0,4*np.pi,50)
@@ -129,7 +126,7 @@ def _test_determinism_save(filename, usetex):
129126
ax.set_xlabel('A string $1+2+\\sigma$')
130127
ax.set_ylabel('A string $1+2+\\sigma$')
131128

132-
FigureCanvasSVG(fig).print_svg(filename)
129+
fig.savefig(filename,format="svg")
133130

134131

135132
@pytest.mark.parametrize(
@@ -172,15 +169,30 @@ def test_determinism(filename, usetex):
172169
@needs_usetex
173170
deftest_missing_psfont(monkeypatch):
174171
"""An error is raised if a TeX font lacks a Type-1 equivalent"""
175-
frommatplotlibimportrc
176172

177173
defpsfont(*args,**kwargs):
178174
returndviread.PsFont(texname='texfont',psname='Some Font',
179175
effects=None,encoding=None,filename=None)
180176

181177
monkeypatch.setattr(dviread.PsfontsMap,'__getitem__',psfont)
182-
rc('text',usetex=True)
178+
mpl.rc('text',usetex=True)
183179
fig,ax=plt.subplots()
184180
ax.text(0.5,0.5,'hello')
185181
withtempfile.TemporaryFile()astmpfile,pytest.raises(ValueError):
186182
fig.savefig(tmpfile,format='svg')
183+
184+
185+
# Use Computer Modern Sans Serif, not Helvetica (which has no \textwon).
186+
@pytest.mark.style('default')
187+
@needs_usetex
188+
deftest_unicode_won():
189+
fig=Figure()
190+
fig.text(.5,.5,r'\textwon',usetex=True)
191+
192+
withBytesIO()asfd:
193+
fig.savefig(fd,format='svg')
194+
buf=fd.getvalue().decode('ascii')
195+
196+
won_id='Computer_Modern_Sans_Serif-142'
197+
assertre.search(r'<path d=(.|\s)*?id="{0}"/>'.format(won_id),buf)
198+
assertre.search(r'<use[^/>]*? xlink:href="#{0}"/>'.format(won_id),buf)

‎lib/matplotlib/textpath.py

Lines changed: 46 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,6 @@
1616
_log=logging.getLogger(__name__)
1717

1818

19-
@functools.lru_cache(1)
20-
def_get_adobe_standard_encoding():
21-
enc_name=dviread.find_tex_file('8a.enc')
22-
enc=dviread.Encoding(enc_name)
23-
return {c:ifori,cinenumerate(enc.encoding)}
24-
25-
2619
classTextToPath(object):
2720
"""A class that converts strings to paths."""
2821

@@ -291,12 +284,8 @@ def get_texmanager(self):
291284

292285
defget_glyphs_tex(self,prop,s,glyph_map=None,
293286
return_new_glyphs_only=False):
294-
"""
295-
Process string *s* with usetex and convert it to a (vertices, codes)
296-
pair.
297-
"""
298-
299-
# Implementation mostly borrowed from pdf backend.
287+
"""Convert the string *s* to vertices and codes using usetex mode."""
288+
# Mostly borrowed from pdf backend.
300289

301290
dvifile=self.get_texmanager().make_dvi(s,self.FONT_SCALE)
302291
withdviread.Dvi(dvifile,self.DPI)asdvi:
@@ -321,21 +310,20 @@ def get_glyphs_tex(self, prop, s, glyph_map=None,
321310
ifchar_idnotinglyph_map:
322311
font.clear()
323312
font.set_size(self.FONT_SCALE,self.DPI)
324-
ifenc:
325-
charcode=enc.get(glyph,None)
326-
else:
327-
charcode=glyph
328-
329-
ft2font_flag=LOAD_TARGET_LIGHT
330-
ifcharcodeisnotNone:
331-
glyph0=font.load_char(charcode,flags=ft2font_flag)
313+
# See comments in _get_ps_font_and_encoding.
314+
ifencisnotNone:
315+
ifglyphnotinenc:
316+
_log.warning(
317+
"The glyph %d of font %s cannot be converted with "
318+
"the encoding; glyph may be wrong.",
319+
glyph,font.fname)
320+
font.load_char(glyph,flags=LOAD_TARGET_LIGHT)
321+
else:
322+
index=font.get_name_index(enc[glyph])
323+
font.load_glyph(index,flags=LOAD_TARGET_LIGHT)
332324
else:
333-
_log.warning("The glyph (%d) of font (%s) cannot be "
334-
"converted with the encoding. Glyph may "
335-
"be wrong.",glyph,font.fname)
336-
337-
glyph0=font.load_char(glyph,flags=ft2font_flag)
338-
325+
index=glyph
326+
font.load_char(index,flags=LOAD_TARGET_LIGHT)
339327
glyph_map_new[char_id]=font.get_path()
340328

341329
glyph_ids.append(char_id)
@@ -363,31 +351,41 @@ def _get_ps_font_and_encoding(texname):
363351
font_bunch=tex_font_map[texname]
364352
iffont_bunch.filenameisNone:
365353
raiseValueError(
366-
("No usable font file found for %s (%s). "
367-
"The font may lack a Type-1 version.")
368-
% (font_bunch.psname,texname))
354+
f"No usable font file found for{font_bunch.psname} "
355+
f"({texname}). The font may lack a Type-1 version.")
369356

370357
font=get_font(font_bunch.filename)
371358

372-
forcharmap_name,charmap_codein [("ADOBE_CUSTOM",1094992451),
373-
("ADOBE_STANDARD",1094995778)]:
374-
try:
375-
font.select_charmap(charmap_code)
376-
except (ValueError,RuntimeError):
377-
pass
378-
else:
379-
break
359+
iffont_bunch.encoding:
360+
# If psfonts.map specifies an encoding, use it: it gives us a
361+
# mapping of glyph indices to Adobe glyph names; use it to convert
362+
# dvi indices to glyph names and use the FreeType-synthesized
363+
# unicode charmap to convert glyph names to glyph indices (with
364+
# FT_Get_Name_Index/get_name_index), and load the glyph using
365+
# FT_Load_Glyph/load_glyph. (That charmap has a coverage at least
366+
# as good as, and possibly better than, the native charmaps.)
367+
enc=dviread._parse_enc(font_bunch.encoding)
380368
else:
381-
charmap_name=""
382-
_log.warning("No supported encoding in font (%s).",
383-
font_bunch.filename)
384-
385-
ifcharmap_name=="ADOBE_STANDARD"andfont_bunch.encoding:
386-
enc0=dviread.Encoding(font_bunch.encoding)
387-
enc= {i:_get_adobe_standard_encoding().get(c,None)
388-
fori,cinenumerate(enc0.encoding)}
389-
else:
390-
enc= {}
369+
# If psfonts.map specifies no encoding, the indices directly
370+
# map to the font's "native" charmap; so don't use the
371+
# FreeType-synthesized charmap but the native ones (we can't
372+
# directly identify it but it's typically an Adobe charmap), and
373+
# directly load the dvi glyph indices using FT_Load_Char/load_char.
374+
forcharmap_name,charmap_codein [
375+
("ADOBE_CUSTOM",1094992451),
376+
("ADOBE_STANDARD",1094995778),
377+
]:
378+
try:
379+
font.select_charmap(charmap_code)
380+
except (ValueError,RuntimeError):
381+
pass
382+
else:
383+
break
384+
else:
385+
charmap_name=""
386+
_log.warning("No supported encoding in font (%s).",
387+
font_bunch.filename)
388+
enc=None
391389

392390
returnfont,enc
393391

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp