10000 Deprecate passing floats to FT2Image · matplotlib/matplotlib@a8ca1c1 · GitHub
[go: up one dir, main page]

Skip to content

Commit a8ca1c1

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

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_ D1AE 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)
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)
0