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

Commitbcd6136

Browse files
committed
Use libraqm for text in vector outputs
1 parentdd5b1da commitbcd6136

File tree

10 files changed

+58
-113
lines changed

10 files changed

+58
-113
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
@@ -220,8 +220,8 @@ def track(self, font: FT2Font, s: str) -> list[tuple[int, CharacterCodeType]]:
220220
and the character codes will be returned from the string unchanged.
221221
"""
222222
return [
223-
self.track_glyph(f,ord(c),f.get_char_index(ord(c)))
224-
forc,finfont._get_fontmap(s).items()
223+
self.track_glyph(raqm_item.ft_object,raqm_item.char,raqm_item.glyph_index)
224+
forraqm_iteminfont._layout(s,ft2font.LoadFlags.NO_HINTING)
225225
]
226226

227227
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
@@ -469,6 +469,7 @@ class Op(Enum):
469469
textpos=b'Td'
470470
selectfont=b'Tf'
471471
textmatrix=b'Tm'
472+
textrise=b'Ts'
472473
show=b'Tj'
473474
showkern=b'TJ'
474475
setlinewidth=b'w'
@@ -2285,6 +2286,8 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
22852286
# If fonttype is neither 3 nor 42, emit the whole string at once
22862287
# without manual kerning.
22872288
iffonttypenotin [3,42]:
2289+
ifnotmpl.rcParams['pdf.use14corefonts']:
2290+
self.file._character_tracker.track(font,s)
22882291
self.file.output(Op.begin_text,
22892292
self.file.fontName(prop),fontsize,Op.selectfont)
22902293
self._setup_textpos(x,y,angle)
@@ -2305,13 +2308,16 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
23052308
# kerning between chunks.
23062309
else:
23072310
defoutput_singlebyte_chunk(kerns_or_chars):
2311+
ifnotkerns_or_chars:
2312+
return
23082313
self.file.output(
23092314
# See pdf spec "Text space details" for the 1000/fontsize
23102315
# (aka. 1000/T_fs) factor.
23112316
[(-1000*next(group)/fontsize)iftp==float# a kern
23122317
elseself._encode_glyphs(group,fonttype)
23132318
fortp,groupinitertools.groupby(kerns_or_chars,type)],
23142319
Op.showkern)
2320+
kerns_or_chars.clear()
23152321
# Do the rotation and global translation as a single matrix
23162322
# concatenation up front
23172323
self.file.output(Op.gsave)
@@ -2326,24 +2332,26 @@ def output_singlebyte_chunk(kerns_or_chars):
23262332
# Emit all the characters in a BT/ET group.
23272333
self.file.output(Op.begin_text)
23282334
foritemin_text_helpers.layout(s,font,features=features,
2329-
kern_mode=Kerning.UNFITTED,
23302335
language=language):
23312336
subset,charcode=self.file._character_tracker.track_glyph(
23322337
item.ft_object,item.char,item.glyph_index)
23332338
if (item.ft_object,subset)!=prev_font:
2334-
ifsinglebyte_chunk:
2335-
output_singlebyte_chunk(singlebyte_chunk)
2339+
output_singlebyte_chunk(singlebyte_chunk)
23362340
ft_name=self.file.fontName(item.ft_object.fname,subset)
23372341
self.file.output(ft_name,fontsize,Op.selectfont)
23382342
self._setup_textpos(item.x,0,0,prev_start_x,0,0)
2339-
singlebyte_chunk= []
23402343
prev_font= (item.ft_object,subset)
23412344
prev_start_x=item.x
2345+
ifitem.y:
2346+
output_singlebyte_chunk(singlebyte_chunk)
2347+
self.file.output(item.y,Op.textrise)
23422348
ifitem.prev_kern:
23432349
singlebyte_chunk.append(item.prev_kern)
23442350
singlebyte_chunk.append(charcode)
2345-
ifsinglebyte_chunk:
2346-
output_singlebyte_chunk(singlebyte_chunk)
2351+
ifitem.y:
2352+
output_singlebyte_chunk(singlebyte_chunk)
2353+
self.file.output(0,Op.textrise)
2354+
output_singlebyte_chunk(singlebyte_chunk)
23472355
self.file.output(Op.end_text)
23482356
self.file.output(Op.grestore)
23492357

‎lib/matplotlib/backends/backend_ps.py‎

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -776,7 +776,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
776776
ifismath:
777777
returnself.draw_mathtext(gc,x,y,s,prop,angle)
778778

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

781781
ifmpl.rcParams['ps.useafm']:
782782
font=self._get_font_afm(prop)
@@ -794,7 +794,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
794794
kern=font.get_kern_dist_from_name(last_name,name)
795795
last_name=name
796796
thisx+=kern*scale
797-
stream.append((ps_name,thisx,name))
797+
stream.append((ps_name,thisx,0,name))
798798
thisx+=width*scale
799799

800800
else:
@@ -814,14 +814,13 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
814814
ps_name= (item.ft_object.postscript_name
815815
.encode("ascii","replace").decode("ascii"))
816816
glyph_name=item.ft_object.get_glyph_name(item.glyph_index)
817-
stream.append((f'{ps_name}-{subset}',item.x,glyph_name))
817+
stream.append((f'{ps_name}-{subset}',item.x,item.y,glyph_name))
818818
self.set_color(*gc.get_rgb())
819819

820-
forps_name,groupinitertools. \
821-
groupby(stream,lambdaentry:entry[0]):
820+
forps_name,groupinitertools.groupby(stream,lambdaentry:entry[0]):
822821
self.set_font(ps_name,prop.get_size_in_points(),False)
823-
thetext="\n".join(f"{x:g}0 m /{name:s} glyphshow"
824-
for_,x,nameingroup)
822+
thetext="\n".join(f"{x:g}{y:g} m /{name:s} glyphshow"
823+
for_,x,y,nameingroup)
825824
self._pswriter.write(f"""\
826825
gsave
827826
{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: 5 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'],extensions=['png','pdf','svg','eps'])
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,8 @@ 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(['features'],remove_text=False,style='mpl20',
1208+
extensions=['png','pdf','svg','eps'])
12081209
deftest_text_features():
12091210
fig=plt.figure(figsize=(5,1.5))
12101211
t=fig.text(1,0.7,'Default: fi ffi fl st',
@@ -1234,7 +1235,8 @@ def test_text_language_invalid(input, match):
12341235
Text(0,0,'foo',language=input)
12351236

12361237

1237-
@image_comparison(baseline_images=['language.png'],remove_text=False,style='mpl20')
1238+
@image_comparison(['language'],remove_text=False,style='mpl20',
1239+
extensions=['png','pdf','svg','eps'])
12381240
deftest_text_language():
12391241
fig=plt.figure(figsize=(5,3))
12401242

‎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