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

Commite0f4ef1

Browse files
committed
Use libraqm for text in vector outputs
1 parentd5f19e7 commite0f4ef1

File tree

10 files changed

+58
-114
lines changed

10 files changed

+58
-114
lines changed

‎lib/matplotlib/_text_helpers.py‎

Lines changed: 12 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,23 @@
44

55
from __future__importannotations
66

7-
importdataclasses
7+
fromcollections.abcimportIterator
88

99
from .import_api
10-
from .ft2fontimportFT2Font,GlyphIndexType,Kerning,LoadFlags
10+
from .ft2fontimportFT2Font,CharacterCodeType,LayoutItem,LoadFlags
1111

1212

13-
@dataclasses.dataclass(frozen=True)
14-
classLayoutItem:
15-
ft_object:FT2Font
16-
char:str
17-
glyph_index:GlyphIndexType
18-
x:float
19-
prev_kern:float
20-
21-
22-
defwarn_on_missing_glyph(codepoint,fontnames):
13+
defwarn_on_missing_glyph(codepoint:CharacterCodeType,fontnames:str):
2314
_api.warn_external(
2415
f"Glyph{codepoint} "
2516
f"({chr(codepoint).encode('ascii','namereplace').decode('ascii')}) "
2617
f"missing from font(s){fontnames}.")
2718

2819

29-
deflayout(string,font,*,features=None,kern_mode=Kerning.DEFAULT,language=None):
20+
deflayout(string:str,font:FT2Font,*,
21+
features:tuple[str]|None=None,
22+
language:str|tuple[tuple[str,int,int], ...]|None=None
23+
)->Iterator[LayoutItem]:
3024
"""
3125
Render *string* with *font*.
3226
@@ -41,8 +35,6 @@ def layout(string, font, *, features=None, kern_mode=Kerning.DEFAULT, language=N
4135
The font.
4236
features : tuple of str, optional
4337
The font features to apply to the text.
44-
kern_mode : Kerning
45-
A FreeType kerning mode.
4638
language : str, optional
4739
The language of the text in a format accepted by libraqm, namely `a BCP47
4840
language code <https://www.w3.org/International/articles/language-tags/>`_.
@@ -51,20 +43,8 @@ def layout(string, font, *, features=None, kern_mode=Kerning.DEFAULT, language=N
5143
------
5244
LayoutItem
5345
"""
54-
x=0
55-
prev_glyph_index=None
56-
char_to_font=font._get_fontmap(string)# TODO: Pass in features and language.
57-
base_font=font
58-
forcharinstring:
59-
# This has done the fallback logic
60-
font=char_to_font.get(char,base_font)
61-
glyph_index=font.get_char_index(ord(char))
62-
kern= (
63-
base_font.get_kerning(prev_glyph_index,glyph_index,kern_mode)/64
64-
ifprev_glyph_indexisnotNoneelse0.
65-
)
66-
x+=kern
67-
glyph=font.load_glyph(glyph_index,flags=LoadFlags.NO_HINTING)
68-
yieldLayoutItem(font,char,glyph_index,x,kern)
69-
x+=glyph.linearHoriAdvance/65536
70-
prev_glyph_index=glyph_index
46+
forraqm_iteminfont._layout(string,LoadFlags.NO_HINTING,
47+
features=features,language=language):
48+
raqm_item.ft_object.load_glyph(raqm_item.glyph_index,
49+
flags=LoadFlags.NO_HINTING)
50+
yieldraqm_item

‎lib/matplotlib/backends/_backend_pdf_ps.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,8 +214,8 @@ def track(self, font: FT2Font, s: str) -> list[tuple[int, CharacterCodeType]]:
214214
and the character codes will be returned from the string unchanged.
215215
"""
216216
return [
217-
self.track_glyph(f,ord(c),f.get_char_index(ord(c)))
218-
forc,finfont._get_fontmap(s).items()
217+
self.track_glyph(raqm_item.ft_object,raqm_item.char,raqm_item.glyph_index)
218+
forraqm_iteminfont._layout(s,ft2font.LoadFlags.NO_HINTING)
219219
]
220220

221221
deftrack_glyph(self,font:FT2Font,chars:str|CharacterCodeType,

‎lib/matplotlib/backends/backend_pdf.py‎

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
frommatplotlib.figureimportFigure
3535
frommatplotlib.font_managerimportget_font,fontManageras_fontManager
3636
frommatplotlib._afmimportAFM
37-
frommatplotlib.ft2fontimportFT2Font,FaceFlags,Kerning,LoadFlags,StyleFlags
37+
frommatplotlib.ft2fontimportFT2Font,FaceFlags,LoadFlags,StyleFlags
3838
frommatplotlib.transformsimportAffine2D,BboxBase
3939
frommatplotlib.pathimportPath
4040
frommatplotlib.datesimportUTC
@@ -475,6 +475,7 @@ class Op(Enum):
475475
textpos=b'Td'
476476
selectfont=b'Tf'
477477
textmatrix=b'Tm'
478+
textrise=b'Ts'
478479
show=b'Tj'
479480
showkern=b'TJ'
480481
setlinewidth=b'w'
@@ -2294,6 +2295,8 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
22942295
# If fonttype is neither 3 nor 42, emit the whole string at once
22952296
# without manual kerning.
22962297
iffonttypenotin [3,42]:
2298+
ifnotmpl.rcParams['pdf.use14corefonts']:
2299+
self.file._character_tracker.track(font,s)
22972300
self.file.output(Op.begin_text,
22982301
self.file.fontName(prop),fontsize,Op.selectfont)
22992302
self._setup_textpos(x,y,angle)
@@ -2314,13 +2317,16 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
23142317
# kerning between chunks.
23152318
else:
23162319
defoutput_singlebyte_chunk(kerns_or_chars):
2320+
ifnotkerns_or_chars:
2321+
return
23172322
self.file.output(
23182323
# See pdf spec "Text space details" for the 1000/fontsize
23192324
# (aka. 1000/T_fs) factor.
23202325
[(-1000*next(group)/fontsize)iftp==float# a kern
23212326
elseself._encode_glyphs(group,fonttype)
23222327
fortp,groupinitertools.groupby(kerns_or_chars,type)],
23232328
Op.showkern)
2329+
kerns_or_chars.clear()
23242330
# Do the rotation and global translation as a single matrix
23252331
# concatenation up front
23262332
self.file.output(Op.gsave)
@@ -2335,24 +2341,26 @@ def output_singlebyte_chunk(kerns_or_chars):
23352341
# Emit all the characters in a BT/ET group.
23362342
self.file.output(Op.begin_text)
23372343
foritemin_text_helpers.layout(s,font,features=features,
2338-
kern_mode=Kerning.UNFITTED,
23392344
language=language):
23402345
subset,charcode=self.file._character_tracker.track_glyph(
23412346
item.ft_object,item.char,item.glyph_index)
23422347
if (item.ft_object,subset)!=prev_font:
2343-
ifsinglebyte_chunk:
2344-
output_singlebyte_chunk(singlebyte_chunk)
2348+
output_singlebyte_chunk(singlebyte_chunk)
23452349
ft_name=self.file.fontName(item.ft_object.fname,subset)
23462350
self.file.output(ft_name,fontsize,Op.selectfont)
23472351
self._setup_textpos(item.x,0,0,prev_start_x,0,0)
2348-
singlebyte_chunk= []
23492352
prev_font= (item.ft_object,subset)
23502353
prev_start_x=item.x
2354+
ifitem.y:
2355+
output_singlebyte_chunk(singlebyte_chunk)
2356+
self.file.output(item.y,Op.textrise)
23512357
ifitem.prev_kern:
23522358
singlebyte_chunk.append(item.prev_kern)
23532359
singlebyte_chunk.append(charcode)
2354-
ifsinglebyte_chunk:
2355-
output_singlebyte_chunk(singlebyte_chunk)
2360+
ifitem.y:
2361+
output_singlebyte_chunk(singlebyte_chunk)
2362+
self.file.output(0,Op.textrise)
2363+
output_singlebyte_chunk(singlebyte_chunk)
23562364
self.file.output(Op.end_text)
23572365
self.file.output(Op.grestore)
23582366

‎lib/matplotlib/backends/backend_ps.py‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -769,7 +769,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
769769
ifismath:
770770
returnself.draw_mathtext(gc,x,y,s,prop,angle)
771771

772-
stream= []# list of (ps_name, x, char_name)
772+
stream= []# list of (ps_name, x,y,char_name)
773773

774774
ifmpl.rcParams['ps.useafm']:
775775
font=self._get_font_afm(prop)
@@ -787,7 +787,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
787787
kern=font.get_kern_dist_from_name(last_name,name)
788788
last_name=name
789789
thisx+=kern*scale
790-
stream.append((ps_name,thisx,name))
790+
stream.append((ps_name,thisx,0,name))
791791
thisx+=width*scale
792792

793793
else:
@@ -797,20 +797,20 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
797797
else:
798798
features=language=None
799799
font=self._get_font_ttf(prop)
800-
self._character_tracker.track(font,s)
801800
foritemin_text_helpers.layout(s,font,features=features,
802801
language=language):
802+
self._character_tracker.track_glyph(item.ft_object,ord(item.char),
803+
item.glyph_index)
803804
ps_name= (item.ft_object.postscript_name
804805
.encode("ascii","replace").decode("ascii"))
805806
glyph_name=item.ft_object.get_glyph_name(item.glyph_index)
806-
stream.append((ps_name,item.x,glyph_name))
807+
stream.append((ps_name,item.x,item.y,glyph_name))
807808
self.set_color(*gc.get_rgb())
808809

809-
forps_name,groupinitertools. \
810-
groupby(stream,lambdaentry:entry[0]):
810+
forps_name,groupinitertools.groupby(stream,lambdaentry:entry[0]):
811811
self.set_font(ps_name,prop.get_size_in_points(),False)
812-
thetext="\n".join(f"{x:g}0 m /{name:s} glyphshow"
813-
for_,x,nameingroup)
812+
thetext="\n".join(f"{x:g}{y:g} m /{name:s} glyphshow"
813+
for_,x,y,nameingroup)
814814
self._pswriter.write(f"""\
815815
gsave
816816
{self._get_clip_cmd(gc)}

‎lib/matplotlib/backends/backend_svg.py‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1048,6 +1048,11 @@ def _draw_text_as_path(self, gc, x, y, s, prop, angle, ismath, mtext=None):
10481048
text2path=self._text2path
10491049
color=rgb2hex(gc.get_rgb())
10501050
fontsize=prop.get_size_in_points()
1051+
ifmtextisnotNone:
1052+
features=mtext.get_fontfeatures()
1053+
language=mtext.get_language()
1054+
else:
1055+
features=language=None
10511056

10521057
style= {}
10531058
ifcolor!='#000000':
@@ -1068,7 +1073,8 @@ def _draw_text_as_path(self, gc, x, y, s, prop, angle, ismath, mtext=None):
10681073
ifnotismath:
10691074
font=text2path._get_font(prop)
10701075
glyph_info,glyph_map_new,rects=text2path.get_glyphs_with_font(
1071-
font,s,glyph_map=glyph_map,return_new_glyphs_only=True)
1076+
font,s,features=features,language=language,
1077+
glyph_map=glyph_map,return_new_glyphs_only=True)
10721078
self._update_glyph_map_defs(glyph_map_new)
10731079

10741080
forglyph_repr,xposition,yposition,scaleinglyph_info:

‎lib/matplotlib/ft2font.pyi‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,6 @@ class FT2Font(Buffer):
219219
)->None: ...
220220
ifsys.version_info[:2]>= (3,12):
221221
def__buffer__(self,flags:int)->memoryview: ...
222-
def_get_fontmap(self,string:str)->dict[str,FT2Font]: ...
223222
def_layout(
224223
self,
225224
text:str,

‎lib/matplotlib/tests/test_ft2font.py‎

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -972,7 +972,7 @@ def test_fallback_last_resort(recwarn):
972972
"Glyph 128579 (\\N{UPSIDE-DOWN FACE}) missing from font(s)")
973973

974974

975-
deftest__get_fontmap():
975+
deftest__layout():
976976
fonts,test_str=_gen_multi_font_text()
977977
# Add some glyphs that don't exist in either font to check the Last Resort fallback.
978978
missing_glyphs='\n几个汉字'
@@ -981,11 +981,11 @@ def test__get_fontmap():
981981
ft=fm.get_font(
982982
fm.fontManager._find_fonts_by_props(fm.FontProperties(family=fonts))
983983
)
984-
fontmap=ft._get_fontmap(test_str)
985-
forchar,fontinfontmap.items():
986-
ifcharinmissing_glyphs:
987-
assertPath(font.fname).name=='LastResortHE-Regular.ttf'
988-
eliford(char)>127:
989-
assertPath(font.fname).name=='DejaVuSans.ttf'
990-
else:
991-
assertPath(font.fname).name=='cmr10.ttf'
984+
forsubstrintest_str.split('\n'):
985+
foriteminft._layout(substr,ft2font.LoadFlags.DEFAULT):
986+
ifitem.charinmissing_glyphs:
987+
assertPath(item.ft_object.fname).name=='LastResortHE-Regular.ttf'
988+
eliford(item.char)>127:
989+
assertPath(item.ft_object.fname).name=='DejaVuSans.ttf'
990+
else:
991+
assertPath(item.ft_object.fname).name=='cmr10.ttf'

‎lib/matplotlib/tests/test_text.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ def find_matplotlib_font(**kw):
113113
ax.set_yticks([])
114114

115115

116-
@image_comparison(['complex.png'])
116+
@image_comparison(['complex'])
117117
deftest_complex_shaping():
118118
# Raqm is Arabic for writing; note that because Arabic is RTL, the characters here
119119
# may seem to be in a different order than expected, but libraqm will order them
@@ -1204,7 +1204,7 @@ def test_ytick_rotation_mode():
12041204
plt.subplots_adjust(left=0.4,right=0.6,top=.99,bottom=.01)
12051205

12061206

1207-
@image_comparison(baseline_images=['features.png'],remove_text=False,style='mpl20')
1207+
@image_comparison(baseline_images=['features'],remove_text=False,style='mpl20')
12081208
deftest_text_features():
12091209
fig=plt.figure(figsize=(5,1.5))
12101210
t=fig.text(1,0.7,'Default: fi ffi fl st',
@@ -1234,7 +1234,7 @@ def test_text_language_invalid(input, match):
12341234
Text(0,0,'foo',language=input)
12351235

12361236

1237-
@image_comparison(baseline_images=['language.png'],remove_text=False,style='mpl20')
1237+
@image_comparison(baseline_images=['language'],remove_text=False,style='mpl20')
12381238
deftest_text_language():
12391239
fig=plt.figure(figsize=(5,3))
12401240

‎lib/matplotlib/textpath.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,15 +147,16 @@ def get_glyphs_with_font(self, font, s, glyph_map=None,
147147
glyph_map_new=glyph_map
148148

149149
xpositions= []
150+
ypositions= []
150151
glyph_reprs= []
151152
foritemin_text_helpers.layout(s,font,features=features,language=language):
152153
glyph_repr=self._get_glyph_repr(item.ft_object,item.glyph_index)
153154
glyph_reprs.append(glyph_repr)
154155
xpositions.append(item.x)
156+
ypositions.append(item.y)
155157
ifglyph_reprnotinglyph_map:
156158
glyph_map_new[glyph_repr]=item.ft_object.get_path()
157159

158-
ypositions= [0]*len(xpositions)
159160
sizes= [1.]*len(xpositions)
160161

161162
rects= []

‎src/ft2font_wrapper.cpp‎

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -623,54 +623,6 @@ PyFT2Font_get_kerning(PyFT2Font *self, FT_UInt left, FT_UInt right,
623623
return self->get_kerning(left, right, mode);
624624
}
625625

626-
constchar *PyFT2Font_get_fontmap__doc__ =R"""(
627-
Get a mapping between characters and the font that includes them.
628-
629-
.. warning::
630-
This API uses the fallback list and is both private and provisional: do not use
631-
it directly.
632-
633-
Parameters
634-
----------
635-
text : str
636-
The characters for which to find fonts.
637-
638-
Returns
639-
-------
640-
dict[str, FT2Font]
641-
A dictionary mapping unicode characters to `.FT2Font` objects.
642-
)""";
643-
644-
static py::dict
645-
PyFT2Font_get_fontmap(PyFT2Font *self, std::u32string text)
646-
{
647-
std::set<FT_ULong> codepoints;
648-
649-
py::dict char_to_font;
650-
for (auto code : text) {
651-
if (!codepoints.insert(code).second) {
652-
continue;
653-
}
654-
655-
py::object target_font;
656-
int index;
657-
if (self->get_char_fallback_index(code, index)) {
658-
if (index >=0) {
659-
target_font = self->fallbacks[index];
660-
}else {
661-
target_font =py::cast(self);
662-
}
663-
}else {
664-
// TODO Handle recursion!
665-
target_font =py::cast(self);
666-
}
667-
668-
auto key =py::cast(std::u32string(1, code));
669-
char_to_font[key] = target_font;
670-
}
671-
return char_to_font;
672-
}
673-
674626
constchar *PyFT2Font_set_text__doc__ =R"""(
675627
Set the text *string* and *angle*.
676628
@@ -1705,8 +1657,6 @@ PYBIND11_MODULE(ft2font, m, py::mod_gil_not_used())
17051657
"string"_a,"angle"_a=0.0,"flags"_a=LoadFlags::FORCE_AUTOHINT,py::kw_only(),
17061658
"features"_a=nullptr,"language"_a=nullptr,
17071659
PyFT2Font_set_text__doc__)
1708-
.def("_get_fontmap", &PyFT2Font_get_fontmap,"string"_a,
1709-
PyFT2Font_get_fontmap__doc__)
17101660
.def("get_num_glyphs", &PyFT2Font::get_num_glyphs,
17111661
PyFT2Font_get_num_glyphs__doc__)
17121662
.def("load_char", &PyFT2Font_load_char,

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp