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

Commit4c45ae2

Browse files
committed
Use libraqm for text in vector outputs
1 parente771cc4 commit4c45ae2

File tree

6 files changed

+143
-45
lines changed

6 files changed

+143
-45
lines changed

‎lib/matplotlib/_text_helpers.py

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

55
from __future__importannotations
66

7-
importdataclasses
7+
fromcollections.abcimportIterator
88

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

1212

13-
@dataclasses.dataclass(frozen=True)
14-
classLayoutItem:
15-
ft_object:FT2Font
16-
char:str
17-
glyph_idx:int
18-
x:float
19-
prev_kern:float
20-
21-
22-
defwarn_on_missing_glyph(codepoint,fontnames):
13+
defwarn_on_missing_glyph(codepoint:int,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,*,kern_mode=Kerning.DEFAULT):
20+
deflayout(string:str,font:FT2Font)->Iterator[LayoutItem]:
3021
"""
3122
Render *string* with *font*.
3223
@@ -39,27 +30,11 @@ def layout(string, font, *, kern_mode=Kerning.DEFAULT):
3930
The string to be rendered.
4031
font : FT2Font
4132
The font.
42-
kern_mode : Kerning
43-
A FreeType kerning mode.
4433
4534
Yields
4635
------
4736
LayoutItem
4837
"""
49-
x=0
50-
prev_glyph_idx=None
51-
char_to_font=font._get_fontmap(string)
52-
base_font=font
53-
forcharinstring:
54-
# This has done the fallback logic
55-
font=char_to_font.get(char,base_font)
56-
glyph_idx=font.get_char_index(ord(char))
57-
kern= (
58-
base_font.get_kerning(prev_glyph_idx,glyph_idx,kern_mode)/64
59-
ifprev_glyph_idxisnotNoneelse0.
60-
)
61-
x+=kern
62-
glyph=font.load_glyph(glyph_idx,flags=LoadFlags.NO_HINTING)
63-
yieldLayoutItem(font,char,glyph_idx,x,kern)
64-
x+=glyph.linearHoriAdvance/65536
65-
prev_glyph_idx=glyph_idx
38+
forraqm_iteminfont._layout(string,LoadFlags.NO_HINTING):
39+
raqm_item.ft_object.load_glyph(raqm_item.glyph_idx,flags=LoadFlags.NO_HINTING)
40+
yieldraqm_item

‎lib/matplotlib/backends/backend_pdf.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
frommatplotlib.figureimportFigure
3636
frommatplotlib.font_managerimportget_font,fontManageras_fontManager
3737
frommatplotlib._afmimportAFM
38-
frommatplotlib.ft2fontimportFT2Font,FaceFlags,Kerning,LoadFlags,StyleFlags
38+
frommatplotlib.ft2fontimportFT2Font,FaceFlags,LoadFlags,StyleFlags
3939
frommatplotlib.transformsimportAffine2D,BboxBase
4040
frommatplotlib.pathimportPath
4141
frommatplotlib.datesimportUTC
@@ -2351,7 +2351,6 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
23512351
fonttype=1
23522352
else:
23532353
font=self._get_font_ttf(prop)
2354-
self.file._character_tracker.track(font,s)
23552354
fonttype=mpl.rcParams['pdf.fonttype']
23562355

23572356
ifgc.get_url()isnotNone:
@@ -2363,6 +2362,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
23632362
# If fonttype is neither 3 nor 42, emit the whole string at once
23642363
# without manual kerning.
23652364
iffonttypenotin [3,42]:
2365+
self.file._character_tracker.track(font,s)
23662366
self.file.output(Op.begin_text,
23672367
self.file.fontName(prop),fontsize,Op.selectfont)
23682368
self._setup_textpos(x,y,angle)
@@ -2389,7 +2389,8 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
23892389
multibyte_glyphs= []
23902390
prev_was_multibyte=True
23912391
prev_font=font
2392-
foritemin_text_helpers.layout(s,font,kern_mode=Kerning.UNFITTED):
2392+
foritemin_text_helpers.layout(s,font):
2393+
self.file._character_tracker.track_glyph(font,item.glyph_idx)
23932394
if_font_supports_glyph(fonttype,ord(item.char)):
23942395
ifprev_was_multibyteoritem.ft_object!=prev_font:
23952396
singlebyte_chunks.append((item.ft_object,item.x, []))

‎lib/matplotlib/backends/backend_ps.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -795,19 +795,18 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
795795

796796
else:
797797
font=self._get_font_ttf(prop)
798-
self._character_tracker.track(font,s)
799798
foritemin_text_helpers.layout(s,font):
799+
self._character_tracker.track_glyph(item.ft_object,item.glyph_idx)
800800
ps_name= (item.ft_object.postscript_name
801801
.encode("ascii","replace").decode("ascii"))
802802
glyph_name=item.ft_object.get_glyph_name(item.glyph_idx)
803-
stream.append((ps_name,item.x,glyph_name))
803+
stream.append((ps_name,item.x,item.y,glyph_name))
804804
self.set_color(*gc.get_rgb())
805805

806-
forps_name,groupinitertools. \
807-
groupby(stream,lambdaentry:entry[0]):
806+
forps_name,groupinitertools.groupby(stream,lambdaentry:entry[0]):
808807
self.set_font(ps_name,prop.get_size_in_points(),False)
809-
thetext="\n".join(f"{x:g}0 m /{name:s} glyphshow"
810-
for_,x,nameingroup)
808+
thetext="\n".join(f"{x:g}{y:g} m /{name:s} glyphshow"
809+
for_,x,y,nameingroup)
811810
self._pswriter.write(f"""\
812811
gsave
813812
{self._get_clip_cmd(gc)}

‎lib/matplotlib/textpath.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,15 +144,16 @@ def get_glyphs_with_font(self, font, s, glyph_map=None,
144144
glyph_map_new=glyph_map
145145

146146
xpositions= []
147+
ypositions= []
147148
glyph_ids= []
148149
foritemin_text_helpers.layout(s,font):
149-
char_id=self._get_char_id(item.ft_object,ord(item.char))
150+
char_id=self._get_char_id(item.ft_object,item.glyph_idx)
150151
glyph_ids.append(char_id)
151152
xpositions.append(item.x)
153+
ypositions.append(item.y)
152154
ifchar_idnotinglyph_map:
153155
glyph_map_new[char_id]=item.ft_object.get_path()
154156

155-
ypositions= [0]*len(xpositions)
156157
sizes= [1.]*len(xpositions)
157158

158159
rects= []

‎src/ft2font.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,16 @@ class FT2Font
171171
returnFT_HAS_KERNING(face);
172172
}
173173

174+
voidset_parent(void *parent)
175+
{
176+
_parent = parent;
177+
}
178+
179+
void *get_parent()const
180+
{
181+
return _parent;
182+
}
183+
174184
private:
175185
WarnFunc ft_glyph_warn;
176186
bool warn_if_used;
@@ -185,6 +195,9 @@ class FT2Font
185195
long hinting_factor;
186196
int kerning_factor;
187197

198+
// Holds the parent PyFT2Font object.
199+
void *_parent;
200+
188201
// prevent copying
189202
FT2Font(const FT2Font &);
190203
FT2Font &operator=(const FT2Font &);

‎src/ft2font_wrapper.cpp

Lines changed: 111 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,7 @@ PyFT2Font_init(py::object filename, long hinting_factor = 8,
499499

500500
self->x =newFT2Font(open_args, hinting_factor, fallback_fonts, ft_glyph_warn,
501501
warn_if_used);
502+
self->x->set_parent(self);
502503

503504
self->x->set_kerning_factor(kerning_factor);
504505

@@ -1467,6 +1468,97 @@ PyFT2Font__get_type1_encoding_vector(PyFT2Font *self)
14671468
return indices;
14681469
}
14691470

1471+
/**********************************************************************
1472+
* Layout items
1473+
**/
1474+
1475+
structLayoutItem {
1476+
PyFT2Font *ft_object;
1477+
std::u32string character;
1478+
int glyph_idx;
1479+
double x;
1480+
double y;
1481+
double prev_kern;
1482+
1483+
LayoutItem(PyFT2Font *f, std::u32string c,int i,double x,double y,double k) :
1484+
ft_object(f), character(c), glyph_idx(i), x(x), y(y), prev_kern(k) {}
1485+
1486+
std::stringto_string()
1487+
{
1488+
std::ostringstream out;
1489+
out <<"LayoutItem(ft_object=" <<PyFT2Font_fname(ft_object);
1490+
out <<", char=" << character[0];
1491+
out <<", glyph_idx=" << glyph_idx;
1492+
out <<", x=" << x;
1493+
out <<", y=" << y;
1494+
out <<", prev_kern=" << prev_kern;
1495+
out <<")";
1496+
return out.str();
1497+
}
1498+
};
1499+
1500+
constchar *PyFT2Font_layout__doc__ =R"""(
1501+
Layout a string and yield information about each used glyph.
1502+
1503+
.. warning::
1504+
This API uses the fallback list and is both private and provisional: do not use
1505+
it directly.
1506+
1507+
Parameters
1508+
----------
1509+
text : str
1510+
The characters for which to find fonts.
1511+
1512+
Returns
1513+
-------
1514+
list[LayoutItem]
1515+
)""";
1516+
1517+
staticauto
1518+
PyFT2Font_layout(PyFT2Font *self, std::u32string text, LoadFlags flags)
1519+
{
1520+
constauto hinting_factor = self->x->get_hinting_factor();
1521+
constauto load_flags =static_cast<FT_Int32>(flags);
1522+
1523+
std::set<FT_String*> glyph_seen_fonts;
1524+
std::vector<raqm_glyph_t> glyphs;
1525+
self->x->layout(text, load_flags, glyph_seen_fonts, glyphs);
1526+
1527+
std::vector<LayoutItem> items;
1528+
1529+
double x =0.0;
1530+
double y =0.0;
1531+
std::optional<double> prev_advance = std::nullopt;
1532+
double prev_x =0.0;
1533+
for (auto &glyph : glyphs) {
1534+
auto ft_object =static_cast<FT2Font *>(glyph.ftface->generic.data);
1535+
auto pyft_object =static_cast<PyFT2Font *>(ft_object->get_parent());
1536+
1537+
ft_object->load_glyph(glyph.index, load_flags);
1538+
1539+
double prev_kern =0.0;
1540+
if (prev_advance.has_value()) {
1541+
double actual_advance = (x + glyph.x_offset) - prev_x;
1542+
prev_kern = actual_advance - prev_advance.value();
1543+
}
1544+
1545+
items.emplace_back(pyft_object, text.substr(glyph.cluster,1), glyph.index,
1546+
(x + glyph.x_offset) /64.0, (y + glyph.y_offset) /64.0,
1547+
prev_kern /64.0);
1548+
prev_x = x + glyph.x_offset;
1549+
x += glyph.x_advance;
1550+
y += glyph.y_advance;
1551+
// Note, linearHoriAdvance is a 16.16 instead of 26.6 fixed-point value.
1552+
prev_advance = ft_object->get_face()->glyph->linearHoriAdvance /1024.0 / hinting_factor;
1553+
}
1554+
1555+
return items;
1556+
}
1557+
1558+
/**********************************************************************
1559+
* Deprecations
1560+
**/
1561+
14701562
static py::object
14711563
ft2font__getattr__(std::string name) {
14721564
auto api =py::module_::import("matplotlib._api");
@@ -1601,8 +1693,23 @@ PYBIND11_MODULE(ft2font, m, py::mod_gil_not_used())
16011693
.def_property_readonly("bbox", &PyGlyph_get_bbox,
16021694
"The control box of the glyph.");
16031695

1604-
auto cls = py::class_<PyFT2Font>(m,"FT2Font",py::is_final(),py::buffer_protocol(),
1605-
PyFT2Font__doc__)
1696+
py::class_<LayoutItem>(m,"LayoutItem",py::is_final())
1697+
.def_readonly("ft_object", &LayoutItem::ft_object,
1698+
"The FT_Face of the item.")
1699+
.def_readonly("char", &LayoutItem::character,
1700+
"The character code for the item.")
1701+
.def_readonly("glyph_idx", &LayoutItem::glyph_idx,
1702+
"The glyph index for the item.")
1703+
.def_readonly("x", &LayoutItem::x,
1704+
"The x position of the item.")
1705+
.def_readonly("y", &LayoutItem::y,
1706+
"The y position of the item.")
1707+
.def_readonly("prev_kern", &LayoutItem::prev_kern,
1708+
"The kerning between this item and the previous one.")
1709+
.def("__str__", &LayoutItem::to_string);
1710+
1711+
auto cls = py::class_<PyFT2Font>(m,"FT2Font",py::is_final(),py::buffer_protocol(),
1712+
PyFT2Font__doc__)
16061713
.def(py::init(&PyFT2Font_init),
16071714
"filename"_a,"hinting_factor"_a=8,py::kw_only(),
16081715
"_fallback_list"_a=py::none(),"_kerning_factor"_a=0,
@@ -1617,6 +1724,8 @@ PYBIND11_MODULE(ft2font, m, py::mod_gil_not_used())
16171724
PyFT2Font_select_charmap__doc__)
16181725
.def("get_kerning", &PyFT2Font_get_kerning,"left"_a,"right"_a,"mode"_a,
16191726
PyFT2Font_get_kerning__doc__)
1727+
.def("_layout", &PyFT2Font_layout,"string"_a,"flags"_a,
1728+
PyFT2Font_layout__doc__)
16201729
.def("set_text", &PyFT2Font_set_text,
16211730
"string"_a,"angle"_a=0.0,"flags"_a=LoadFlags::FORCE_AUTOHINT,
16221731
PyFT2Font_set_text__doc__)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp