Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4d40c1b

Browse files
committed
Deprecate passing floats to FT2Image
These were silently truncated to int anyway, so we should make the types explicit.
1 parent 422b6cf commit 4d40c1b

File tree

4 files changed

+59
-10
lines changed

4 files changed

+59
-10
lines changed

doc/api/next_api_changes/deprecations/28967-ES.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,10 @@ Passing floating-point values to ``RendererAgg.draw_text_image``
33

44
Any floating-point values passed to the *x* and *y* parameters were truncated to integers
55
silently. This behaviour is now deprecated, and only `int` values should be used.
6+
7+
Passing floating-point values to ``FT2Image``
8+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9+
10+
Any floating-point values passed to the `.FT2Image` constructor, or the *x0*, *y0*, *x1*,
11+
and *y1* parameters of `.FT2Image.draw_rect_filled` were truncated to integers silently.
12+
This behaviour is now deprecated, and only `int` values should be used.

lib/matplotlib/_mathtext.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ def to_raster(self, *, antialiased: bool) -> RasterParse:
153153
w = xmax - xmin
154154
h = ymax - ymin - self.box.depth
155155
d = ymax - ymin - self.box.height
156-
image = FT2Image(np.ceil(w), np.ceil(h + max(d, 0)))
156+
image = FT2Image(int(np.ceil(w)), int(np.ceil(h + max(d, 0))))
157157

158158
# Ideally, we could just use self.glyphs and self.rects here, shifting
159159
# their coordinates by (-xmin, -ymin), but this yields slightly
@@ -163,7 +163,7 @@ def to_raster(self, *, antialiased: bool) -> RasterParse:
163163

164164
for ox, oy, info in shifted.glyphs:
165165
info.font.draw_glyph_to_bitmap(
166-
image, ox, oy - info.metrics.iceberg, info.glyph,
166+
image, int(ox), int(oy - info.metrics.iceberg), info.glyph,
167167
antialiased=antialiased)
168168
for x1, y1, x2, y2 in shifted.rects:
169169
height = max(int(y2 - y1) - 1, 0)
@@ -172,7 +172,7 @@ def to_raster(self, *, antialiased: bool) -> RasterParse:
172172
y = int(center - (height + 1) / 2)
173173
else:
174174
y = int(y1)
175-
image.draw_rect_filled(int(x1), y, np.ceil(x2), y + height)
175+
image.draw_rect_filled(int(x1), y, int(np.ceil(x2)), y + height)
176176
return RasterParse(0, 0, w, h + d, d, image)
177177

178178

lib/matplotlib/ft2font.pyi

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ class FT2Font(Buffer):
198198
def _get_fontmap(self, string: str) -> dict[str, FT2Font]: ...
199199
def clear(self) -> None: ...
200200
def draw_glyph_to_bitmap(
201-
self, image: FT2Image, x: float, y: float, glyph: Glyph, antialiased: bool = ...
201+
self, image: FT2Image, x: int, y: int, glyph: Glyph, antialiased: bool = ...
202202
) -> None: ...
203203
def draw_glyphs_to_bitmap(self, antialiased: bool = ...) -> None: ...
204204
def get_bitmap_offset(self) -> tuple[int, int]: ...
@@ -281,8 +281,8 @@ class FT2Font(Buffer):
281281

282282
@final
283283
class FT2Image(Buffer):
284-
def __init__(self, width: float, height: float) -> None: ...
285-
def draw_rect_filled(self, x0: float, y0: float, x1: float, y1: float) -> None: ...
284+
def __init__(self, width: int, height: int) -> None: ...
285+
def draw_rect_filled(self, x0: int, y0: int, x1: int, y1: int) -> None: ...
286286
if sys.version_info[:2] >= (3, 12):
287287
def __buffer__(self, flags: int) -> memoryview: ...
288288

src/ft2font_wrapper.cpp

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,30 @@
1313
namespace py = pybind11;
1414
using namespace pybind11::literals;
1515

16+
template <typename T>
17+
using double_or_ = std::variant<double, T>;
18+
19+
template <typename T>
20+
static T
21+
_double_to_(const char *name, double_or_<T> &var)
22+
{
23+
if (auto value = std::get_if<double>(&var)) {
24+
auto api = py::module_::import("matplotlib._api");
25+
auto warn = api.attr("warn_deprecated");
26+
warn("since"_a="3.10", "name"_a=name, "obj_type"_a="parameter as float",
27+
"alternative"_a="int({})"_s.format(name));
28+
return static_cast<T>(*value);
29+
} else if (auto value = std::get_if<T>(&var)) {
30+
return *value;
31+
} else {
32+
// pybind11 will have only allowed types that match the variant, so this `else`
33+
// can't happen. We only have this case because older macOS doesn't support
34+
// `std::get` and using the conditional `std::get_if` means an `else` to silence
35+
// compiler warnings about "unhandled" cases.
36+
throw std::runtime_error("Should not happen");
37+
}
38+
}
39+
1640
/**********************************************************************
1741
* Enumerations
1842
* */
@@ -227,8 +251,15 @@ const char *PyFT2Image_draw_rect_filled__doc__ = R"""(
227251
)""";
228252

229253
static void
230-
PyFT2Image_draw_rect_filled(FT2Image *self, double x0, double y0, double x1, double y1)
254+
PyFT2Image_draw_rect_filled(FT2Image *self,
255+
double_or_<long> vx0, double_or_<long> vy0,
256+
double_or_<long> vx1, double_or_<long> vy1)
231257
{
258+
auto x0 = _double_to_<long>("x0", vx0);
259+
auto y0 = _double_to_<long>("y0", vy0);
260+
auto x1 = _double_to_<long>("x1", vx1);
261+
auto y1 = _double_to_<long>("y1", vy1);
262+
232263
self->draw_rect_filled(x0, y0, x1, y1);
233264
}
234265

@@ -920,7 +951,7 @@ const char *PyFT2Font_draw_glyph_to_bitmap__doc__ = R"""(
920951
----------
921952
image : FT2Image
922953
The image buffer on which to draw the glyph.
923-
x, y : float
954+
x, y : int
924955
The pixel location at which to draw the glyph.
925956
glyph : Glyph
926957
The glyph to draw.
@@ -933,9 +964,13 @@ const char *PyFT2Font_draw_glyph_to_bitmap__doc__ = R"""(
933964
)""";
934965

935966
static void
936-
PyFT2Font_draw_glyph_to_bitmap(PyFT2Font *self, FT2Image &image, double xd, double yd,
967+
PyFT2Font_draw_glyph_to_bitmap(PyFT2Font *self, FT2Image &image,
968+
double_or_<int> vxd, double_or_<int> vyd,
937969
PyGlyph *glyph, bool antialiased = true)
938970
{
971+
auto xd = _double_to_<int>("x", vxd);
972+
auto yd = _double_to_<int>("y", vyd);
973+
939974
self->x->draw_glyph_to_bitmap(image, xd, yd, glyph->glyphInd, antialiased);
940975
}
941976

@@ -1625,7 +1660,14 @@ PYBIND11_MODULE(ft2font, m, py::mod_gil_not_used())
16251660

16261661
py::class_<FT2Image>(m, "FT2Image", py::is_final(), py::buffer_protocol(),
16271662
PyFT2Image__doc__)
1628-
.def(py::init<double, double>(), "width"_a, "height"_a, PyFT2Image_init__doc__)
1663+
.def(py::init(
1664+
[](double_or_<long> width, double_or_<long> height) {
1665+
return new FT2Image(
1666+
_double_to_<long>("width", width),
1667+
_double_to_<long>("height", height)
1668+
);
1669+
}),
1670+
"width"_a, "height"_a, PyFT2Image_init__doc__)
16291671
.def("draw_rect_filled", &PyFT2Image_draw_rect_filled,
16301672
"x0"_a, "y0"_a, "x1"_a, "y1"_a,
16311673
PyFT2Image_draw_rect_filled__doc__)

0 commit comments

Comments
 (0)