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

Commit7a760d1

Browse files
committed
Rework mapping of dvi glyph indices to freetype indices.
In89a7e19, an API for converting "dvi glyph indices" (as storedin a dvi file) to FreeType-compatible keys (either "indices intothe native charmap" or "glyph names") was introduced. It wasintended that end users (i.e., backends) would check the type of`text.glyph_name_or_index` ((A) int or (B) str) and load the glyphaccordingly ((A) `FT_Set_Charmap(native_cmap); FT_Load_Char(index);` or(B) `FT_Load_Glyph(FT_Get_Name_Index(name));`); however, with the futureintroduction of {xe,lua}tex support, this kind of type checking becomesinconvenient, because {xe,lua}tex's "dvi glyph indices", which aredirectly equal to FreeType glyph indices (i.e. they would be loaded with`FT_Load_Glyph(index);`), would normally also be converted to ints.This PR introduces a new API (`_index_dvi_to_freetype`) to performthis mapping, always mapping to FreeType glyph indices (i.e. onecan always just call `FT_Load_Glyph` on the result). To do so,in case (A) it loads itself the native charmap (something theend user needed to do by themselves previously) and performs thecmap-to-index conversion (`FT_Get_Char_Index`) previously implicitin `FT_Load_Char`; in case (B) it performs itself the name-to-indexconversion (`FT_Get_Name_Index`). When {xe,lua}tex support isintroduced in the future, `_index_dvi_to_freetype` will just return theindex as is. Note that this API is intentionally kept private for now(even though it is used by textpath) and the old APIs are not deprecatedyet; I intend to wait until {xe,lua}tex support is actually merged to doso, to avoid possible future back-and-forth changes on the public APIs.In case (A), this PR also improves on the detection of the nativecharmap, which was previously detected via heuristics(`_select_native_charmap`), but is now read by directly accessing theType 1 font "encoding vector".
1 parent7d5d027 commit7a760d1

File tree

3 files changed

+65
-39
lines changed

3 files changed

+65
-39
lines changed

‎lib/matplotlib/dviread.py

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131

3232
importnumpyasnp
3333

34-
frommatplotlibimport_api,cbook
34+
frommatplotlibimport_api,cbook,font_manager
3535

3636
_log=logging.getLogger(__name__)
3737

@@ -579,7 +579,7 @@ class DviFont:
579579
Size of the font in Adobe points, converted from the slightly
580580
smaller TeX points.
581581
"""
582-
__slots__= ('texname','size','_scale','_vf','_tfm')
582+
__slots__= ('texname','size','_scale','_vf','_tfm','_encoding')
583583

584584
def__init__(self,scale,tfm,texname,vf):
585585
_api.check_isinstance(bytes,texname=texname)
@@ -588,6 +588,7 @@ def __init__(self, scale, tfm, texname, vf):
588588
self.texname=texname
589589
self._vf=vf
590590
self.size=scale* (72.0/ (72.27*2**16))
591+
self._encoding=None
591592

592593
widths=_api.deprecated("3.11")(property(lambdaself: [
593594
(1000*self._tfm.width.get(char,0))>>20
@@ -630,6 +631,35 @@ def _height_depth_of(self, char):
630631
hd[-1]=0
631632
returnhd
632633

634+
# TODO: Make this public when {xe,lua}tex support is merged; simultaneously
635+
# deprecate Text.glyph_name_or_index.
636+
def_index_dvi_to_freetype(self,idx):
637+
"""Convert dvi glyph indices to FreeType ones."""
638+
# Glyphs indices stored in the dvi file map to FreeType glyph indices
639+
# (i.e., which can be passed to FT_Load_Glyph) in various ways:
640+
# - if pdftex.map specifies an ".enc" file for the font, that file maps
641+
# dvi indices to Adobe glyph names, which can then be converted to
642+
# FreeType glyph indices with FT_Get_Name_Index.
643+
# - if no ".enc" file is specified, then the font must be a Type 1
644+
# font, and dvi indices directly index into the font's CharStrings
645+
# vector.
646+
# - (xetex & luatex, currently unsupported, can also declare "native
647+
# fonts", for which dvi indices are equal to FreeType indices.)
648+
ifself._encodingisNone:
649+
psfont=PsfontsMap(find_tex_file("pdftex.map"))[self.texname]
650+
ifpsfont.filenameisNone:
651+
raiseValueError("No usable font file found for {} ({}); "
652+
"the font may lack a Type-1 version"
653+
.format(psfont.psname.decode("ascii"),
654+
psfont.texname.decode("ascii")))
655+
face=font_manager.get_font(psfont.filename)
656+
ifpsfont.encoding:
657+
self._encoding= [face.get_name_index(name)
658+
fornamein_parse_enc(psfont.encoding)]
659+
else:
660+
self._encoding=face._get_type1_encoding_vector()
661+
returnself._encoding[idx]
662+
633663

634664
classVf(Dvi):
635665
r"""
@@ -1023,8 +1053,7 @@ def _parse_enc(path):
10231053
Returns
10241054
-------
10251055
list
1026-
The nth entry of the list is the PostScript glyph name of the nth
1027-
glyph.
1056+
The nth list item is the PostScript glyph name of the nth glyph.
10281057
"""
10291058
no_comments=re.sub("%.*","",Path(path).read_text(encoding="ascii"))
10301059
array=re.search(r"(?s)\[(.*)\]",no_comments).group(1)
@@ -1155,15 +1184,10 @@ def _print_fields(*args):
11551184
print(f"font:{font.texname.decode('latin-1')} "
11561185
f"(scale:{font._scale/2**20}) at{fontpath}")
11571186
face=FT2Font(fontpath)
1158-
TextToPath._select_native_charmap(face)
11591187
_print_fields("x","y","glyph","chr","w")
11601188
fortextingroup:
1161-
ifpsfont.encoding:
1162-
glyph_name=_parse_enc(psfont.encoding)[text.glyph]
1163-
else:
1164-
glyph_name=face.get_glyph_name(
1165-
face.get_char_index(text.glyph))
1166-
glyph_str=fontTools.agl.toUnicode(glyph_name)
1189+
glyph_str=fontTools.agl.toUnicode(
1190+
face.get_glyph_name(font._index_dvi_to_freetype(text.glyph)))
11671191
_print_fields(text.x,text.y,text.glyph,glyph_str,text.width)
11681192
ifpage.boxes:
11691193
print("--- BOXES ---")

‎lib/matplotlib/textpath.py

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -238,17 +238,8 @@ def get_glyphs_tex(self, prop, s, glyph_map=None,
238238
ifchar_idnotinglyph_map:
239239
font.clear()
240240
font.set_size(self.FONT_SCALE,self.DPI)
241-
glyph_name_or_index=text.glyph_name_or_index
242-
ifisinstance(glyph_name_or_index,str):
243-
index=font.get_name_index(glyph_name_or_index)
244-
font.load_glyph(index,flags=LoadFlags.TARGET_LIGHT)
245-
elifisinstance(glyph_name_or_index,int):
246-
self._select_native_charmap(font)
247-
font.load_char(
248-
glyph_name_or_index,flags=LoadFlags.TARGET_LIGHT)
249-
else:# Should not occur.
250-
raiseTypeError(f"Glyph spec of unexpected type: "
251-
f"{glyph_name_or_index!r}")
241+
idx=text.font._index_dvi_to_freetype(text.glyph)
242+
font.load_glyph(idx,flags=LoadFlags.TARGET_LIGHT)
252243
glyph_map_new[char_id]=font.get_path()
253244

254245
glyph_ids.append(char_id)
@@ -269,23 +260,6 @@ def get_glyphs_tex(self, prop, s, glyph_map=None,
269260
return (list(zip(glyph_ids,xpositions,ypositions,sizes)),
270261
glyph_map_new,myrects)
271262

272-
@staticmethod
273-
def_select_native_charmap(font):
274-
# Select the native charmap. (we can't directly identify it but it's
275-
# typically an Adobe charmap).
276-
forcharmap_codein [
277-
1094992451,# ADOBE_CUSTOM.
278-
1094995778,# ADOBE_STANDARD.
279-
]:
280-
try:
281-
font.select_charmap(charmap_code)
282-
except (ValueError,RuntimeError):
283-
pass
284-
else:
285-
break
286-
else:
287-
_log.warning("No supported encoding in font (%s).",font.fname)
288-
289263

290264
text_to_path=TextToPath()
291265

‎src/ft2font_wrapper.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1431,6 +1431,32 @@ PyFT2Font_get_image(PyFT2Font *self)
14311431
return py::array_t<unsignedchar>(dims, im.get_buffer());
14321432
}
14331433

1434+
constchar *PyFT2Font__get_type1_encoding_vector__doc__ =R"""(
1435+
Return a list mapping CharString indices of a Type 1 font to FreeType glyph indices.
1436+
1437+
Returns
1438+
-------
1439+
list[int]
1440+
)""";
1441+
1442+
static std::array<FT_UInt,256>
1443+
PyFT2Font__get_type1_encoding_vector(PyFT2Font *self)
1444+
{
1445+
auto face = self->x->get_face();
1446+
auto indices = std::array<FT_UInt,256>{};
1447+
for (auto i =0; i < indices.size(); ++i) {
1448+
auto len =FT_Get_PS_Font_Value(face, PS_DICT_ENCODING_ENTRY, i,nullptr,0);
1449+
if (len == -1) {
1450+
throw std::runtime_error{
1451+
"FT_Get_PS_Font_Value tried to access a non-existent value"};
1452+
}
1453+
auto buf = std::unique_ptr<char[]>{newchar[len]};
1454+
FT_Get_PS_Font_Value(face, PS_DICT_ENCODING_ENTRY, i, buf.get(), len);
1455+
indices[i] =FT_Get_Name_Index(face, buf.get());
1456+
}
1457+
return indices;
1458+
}
1459+
14341460
staticconstchar *
14351461
PyFT2Font_postscript_name(PyFT2Font *self)
14361462
{
@@ -1761,6 +1787,8 @@ PYBIND11_MODULE(ft2font, m, py::mod_gil_not_used())
17611787
PyFT2Font_get_sfnt_table__doc__)
17621788
.def("get_path", &PyFT2Font_get_path, PyFT2Font_get_path__doc__)
17631789
.def("get_image", &PyFT2Font_get_image, PyFT2Font_get_image__doc__)
1790+
.def("_get_type1_encoding_vector", &PyFT2Font__get_type1_encoding_vector,
1791+
PyFT2Font__get_type1_encoding_vector__doc__)
17641792

17651793
.def_property_readonly("postscript_name", &PyFT2Font_postscript_name,
17661794
"PostScript name of the font.")

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp