X Tutup
#include #include #include #include "mplutils.h" #include "py_converters.h" #include "_backend_agg.h" namespace py = pybind11; using namespace pybind11::literals; /********************************************************************** * BufferRegion * */ /* TODO: This doesn't seem to be used internally. Remove? */ static void PyBufferRegion_set_x(BufferRegion *self, int x) { self->get_rect().x1 = x; } static void PyBufferRegion_set_y(BufferRegion *self, int y) { self->get_rect().y1 = y; } static py::object PyBufferRegion_get_extents(BufferRegion *self) { agg::rect_i rect = self->get_rect(); return py::make_tuple(rect.x1, rect.y1, rect.x2, rect.y2); } /********************************************************************** * RendererAgg * */ static void PyRendererAgg_draw_path(RendererAgg *self, GCAgg &gc, mpl::PathIterator path, agg::trans_affine trans, py::object rgbFace) { agg::rgba face = rgbFace.cast(); if (!rgbFace.is_none()) { if (gc.forced_alpha || rgbFace.cast().size() == 3) { face.a = gc.alpha; } } self->draw_path(gc, path, trans, face); } static void PyRendererAgg_draw_text_image(RendererAgg *self, py::array_t image_obj, std::variant vx, std::variant vy, double angle, GCAgg &gc) { int x, y; if (auto value = std::get_if(&vx)) { auto api = py::module_::import("matplotlib._api"); auto warn = api.attr("warn_deprecated"); warn("since"_a="3.10", "name"_a="x", "obj_type"_a="parameter as float", "alternative"_a="int(x)"); x = static_cast(*value); } else if (auto value = std::get_if(&vx)) { x = *value; } else { throw std::runtime_error("Should not happen"); } if (auto value = std::get_if(&vy)) { auto api = py::module_::import("matplotlib._api"); auto warn = api.attr("warn_deprecated"); warn("since"_a="3.10", "name"_a="y", "obj_type"_a="parameter as float", "alternative"_a="int(y)"); y = static_cast(*value); } else if (auto value = std::get_if(&vy)) { y = *value; } else { throw std::runtime_error("Should not happen"); } // TODO: This really shouldn't be mutable, but Agg's renderer buffers aren't const. auto image = image_obj.mutable_unchecked<2>(); self->draw_text_image(gc, image, x, y, angle); } static void PyRendererAgg_draw_markers(RendererAgg *self, GCAgg &gc, mpl::PathIterator marker_path, agg::trans_affine marker_path_trans, mpl::PathIterator path, agg::trans_affine trans, py::object rgbFace) { agg::rgba face = rgbFace.cast(); if (!rgbFace.is_none()) { if (gc.forced_alpha || rgbFace.cast().size() == 3) { face.a = gc.alpha; } } self->draw_markers(gc, marker_path, marker_path_trans, path, trans, face); } static void PyRendererAgg_draw_image(RendererAgg *self, GCAgg &gc, double x, double y, py::array_t image_obj) { // TODO: This really shouldn't be mutable, but Agg's renderer buffers aren't const. auto image = image_obj.mutable_unchecked<3>(); x = mpl_round(x); y = mpl_round(y); gc.alpha = 1.0; self->draw_image(gc, x, y, image); } static void PyRendererAgg_draw_path_collection(RendererAgg *self, GCAgg &gc, agg::trans_affine master_transform, mpl::PathGenerator paths, py::array_t transforms_obj, py::array_t offsets_obj, agg::trans_affine offset_trans, py::array_t facecolors_obj, py::array_t edgecolors_obj, py::array_t linewidths_obj, DashesVector dashes, py::array_t antialiaseds_obj, py::object Py_UNUSED(ignored_obj), // offset position is no longer used py::object Py_UNUSED(offset_position_obj), py::array_t hatchcolors_obj) { auto transforms = convert_transforms(transforms_obj); auto offsets = convert_points(offsets_obj); auto facecolors = convert_colors(facecolors_obj); auto edgecolors = convert_colors(edgecolors_obj); auto hatchcolors = convert_colors(hatchcolors_obj); auto linewidths = linewidths_obj.unchecked<1>(); auto antialiaseds = antialiaseds_obj.unchecked<1>(); self->draw_path_collection(gc, master_transform, paths, transforms, offsets, offset_trans, facecolors, edgecolors, linewidths, dashes, antialiaseds, hatchcolors); } static void PyRendererAgg_draw_quad_mesh(RendererAgg *self, GCAgg &gc, agg::trans_affine master_transform, unsigned int mesh_width, unsigned int mesh_height, py::array_t coordinates_obj, py::array_t offsets_obj, agg::trans_affine offset_trans, py::array_t facecolors_obj, bool antialiased, py::array_t edgecolors_obj) { auto coordinates = coordinates_obj.mutable_unchecked<3>(); auto offsets = convert_points(offsets_obj); auto facecolors = convert_colors(facecolors_obj); auto edgecolors = convert_colors(edgecolors_obj); self->draw_quad_mesh(gc, master_transform, mesh_width, mesh_height, coordinates, offsets, offset_trans, facecolors, antialiased, edgecolors); } static void PyRendererAgg_draw_gouraud_triangles(RendererAgg *self, GCAgg &gc, py::array_t points_obj, py::array_t colors_obj, agg::trans_affine trans) { auto points = points_obj.unchecked<3>(); auto colors = colors_obj.unchecked<3>(); self->draw_gouraud_triangles(gc, points, colors, trans); } PYBIND11_MODULE(_backend_agg, m, py::mod_gil_not_used()) { py::class_(m, "RendererAgg", py::buffer_protocol()) .def(py::init(), "width"_a, "height"_a, "dpi"_a) .def("draw_path", &PyRendererAgg_draw_path, "gc"_a, "path"_a, "trans"_a, "face"_a = nullptr) .def("draw_markers", &PyRendererAgg_draw_markers, "gc"_a, "marker_path"_a, "marker_path_trans"_a, "path"_a, "trans"_a, "face"_a = nullptr) .def("draw_text_image", &PyRendererAgg_draw_text_image, "image"_a, "x"_a, "y"_a, "angle"_a, "gc"_a) .def("draw_image", &PyRendererAgg_draw_image, "gc"_a, "x"_a, "y"_a, "image"_a) .def("draw_path_collection", &PyRendererAgg_draw_path_collection, "gc"_a, "master_transform"_a, "paths"_a, "transforms"_a, "offsets"_a, "offset_trans"_a, "facecolors"_a, "edgecolors"_a, "linewidths"_a, "dashes"_a, "antialiaseds"_a, "ignored"_a, "offset_position"_a, py::kw_only(), "hatchcolors"_a = py::array_t().reshape({0, 4})) .def("draw_quad_mesh", &PyRendererAgg_draw_quad_mesh, "gc"_a, "master_transform"_a, "mesh_width"_a, "mesh_height"_a, "coordinates"_a, "offsets"_a, "offset_trans"_a, "facecolors"_a, "antialiased"_a, "edgecolors"_a) .def("draw_gouraud_triangles", &PyRendererAgg_draw_gouraud_triangles, "gc"_a, "points"_a, "colors"_a, "trans"_a = nullptr) .def("clear", &RendererAgg::clear) .def("copy_from_bbox", &RendererAgg::copy_from_bbox, "bbox"_a) .def("restore_region", py::overload_cast(&RendererAgg::restore_region), "region"_a) .def("restore_region", py::overload_cast(&RendererAgg::restore_region), "region"_a, "xx1"_a, "yy1"_a, "xx2"_a, "yy2"_a, "x"_a, "y"_a) .def_buffer([](RendererAgg *renderer) -> py::buffer_info { std::vector shape { renderer->get_height(), renderer->get_width(), 4 }; std::vector strides { renderer->get_width() * 4, 4, 1 }; return py::buffer_info(renderer->pixBuffer, shape, strides); }); py::class_(m, "BufferRegion", py::buffer_protocol()) // BufferRegion is not constructible from Python, thus no py::init is added. .def("set_x", &PyBufferRegion_set_x) .def("set_y", &PyBufferRegion_set_y) .def("get_extents", &PyBufferRegion_get_extents) .def_buffer([](BufferRegion *buffer) -> py::buffer_info { std::vector shape { buffer->get_height(), buffer->get_width(), 4 }; std::vector strides { buffer->get_width() * 4, 4, 1 }; return py::buffer_info(buffer->get_data(), shape, strides); }); }
X Tutup