Skip to content

Commit 98404c1

Browse files
committed
WIP: Various text rendering strategies.
1 parent 0a25510 commit 98404c1

File tree

2 files changed

+97
-35
lines changed

2 files changed

+97
-35
lines changed

mpl_cairo/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class GraphicsContextRendererCairo(
2727
RendererBase):
2828
def __init__(self, *args, **kwargs):
2929
super().__init__(*args, **kwargs)
30-
self.mathtext_parser = MathTextParser("cairo2")
30+
self.mathtext_parser = MathTextParser("agg")
3131

3232

3333
# Keep the two classes separate, so that we can figure out who inherits what.

src/_mpl_cairo.cpp

+96-34
Original file line numberDiff line numberDiff line change
@@ -199,9 +199,10 @@ void GraphicsContextRenderer::set_linewidth(double lw) {
199199

200200
rgb_t GraphicsContextRenderer::get_rgb(void) {
201201
double r, g, b, a;
202-
if (cairo_pattern_get_rgba(cairo_get_source(cr_), &r, &g, &b, &a)
203-
!= CAIRO_STATUS_SUCCESS) {
204-
throw std::runtime_error("Could not retrieve color from pattern");
202+
auto status = cairo_pattern_get_rgba(cairo_get_source(cr_), &r, &g, &b, &a);
203+
if (status != CAIRO_STATUS_SUCCESS) {
204+
throw std::runtime_error("Could not retrieve color from pattern: "
205+
+ std::string{cairo_status_to_string(status)});
205206
}
206207
return {r, g, b};
207208
}
@@ -261,10 +262,12 @@ void GraphicsContextRenderer::draw_image(
261262
if (im_raw.shape(2) != 4) {
262263
throw std::invalid_argument("RGBA array must have size (m, n, 4)");
263264
}
264-
std::unique_ptr<uint32_t[]> buf{new uint32_t[ni * nj]};
265-
auto ptr = buf.get();
265+
auto stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, nj);
266+
// FIXME We can save a copy in the case where alpha = 1 and the stride is good.
267+
std::unique_ptr<uint8_t[]> buf{new uint8_t[ni * stride]};
266268
if (alpha_) {
267269
for (size_t i = 0; i < ni; ++i) {
270+
auto ptr = reinterpret_cast<uint32_t*>(buf.get() + i * stride);
268271
for (size_t j = 0; j < nj; ++j) {
269272
auto pix = im_raw.data(i, j, 0);
270273
auto r = *(pix++), g = *(pix++), b = *(pix++), a = *(pix++);
@@ -275,6 +278,7 @@ void GraphicsContextRenderer::draw_image(
275278
}
276279
} else {
277280
for (size_t i = 0; i < ni; ++i) {
281+
auto ptr = reinterpret_cast<uint32_t*>(buf.get() + i * stride);
278282
for (size_t j = 0; j < nj; ++j) {
279283
auto pix = im_raw.data(i, j, 0);
280284
auto r = *(pix++), g = *(pix++), b = *(pix++), a = *(pix++);
@@ -285,8 +289,7 @@ void GraphicsContextRenderer::draw_image(
285289
}
286290
}
287291
auto surface = cairo_image_surface_create_for_data(
288-
reinterpret_cast<uint8_t*>(buf.get()), CAIRO_FORMAT_ARGB32,
289-
nj, ni, nj * sizeof(*ptr));
292+
buf.get(), CAIRO_FORMAT_ARGB32, nj, ni, stride);
290293
auto pattern = cairo_pattern_create_for_surface(surface);
291294
cairo_matrix_t matrix{1, 0, 0, -1, -x, -y + get_height()};
292295
cairo_pattern_set_matrix(pattern, &matrix);
@@ -393,34 +396,89 @@ void GraphicsContextRenderer::draw_text(
393396
return;
394397
}
395398
cairo_save(cr_);
396-
cairo_translate(cr_, x, y);
399+
cairo_translate(cr_, int(x), int(y));
397400
cairo_rotate(cr_, -angle * M_PI / 180);
398401
if (ismath) {
399-
auto [width, height, descent, glyphs, rects] =
402+
403+
// // FIXME cairo2 parser
404+
// auto [width, height, descent, glyphs, rects] =
405+
// py::cast(this).attr("mathtext_parser").attr("parse")(s, dpi_, prop)
406+
// .cast<std::tuple<double, double, double,
407+
// std::vector<py::object>, std::vector<py::object>>>();
408+
// for (auto glyph: glyphs) {
409+
// auto [prop, fontsize, c, ox, oy] = glyph
410+
// .cast<std::tuple<py::object, double, std::string, double, double>>();
411+
// cairo_move_to(cr_, ox, oy);
412+
// cairo_select_font_face(
413+
// cr_,
414+
// prop.attr("name").cast<std::string>().c_str(),
415+
// CAIRO_FONT_SLANT_NORMAL,
416+
// CAIRO_FONT_WEIGHT_NORMAL); // FIXME
417+
// cairo_set_font_size(
418+
// cr_,
419+
// points_to_pixels(fontsize));
420+
// cairo_show_text(cr_, c.c_str());
421+
// }
422+
// for (auto rect: rects) {
423+
// auto [ox, oy, w, h] = rect.cast<rectangle_t>();
424+
// cairo_new_path(cr_);
425+
// cairo_rectangle(cr_, ox, oy, w, h);
426+
// cairo_set_source_rgb(cr_, 0, 0, 0);
427+
// cairo_fill(cr_);
428+
// }
429+
430+
// FIXME agg parser, two versions
431+
auto [ox, oy, width, height, descent, image, chars] =
400432
py::cast(this).attr("mathtext_parser").attr("parse")(s, dpi_, prop)
401-
.cast<std::tuple<double, double, double,
402-
std::vector<py::object>, std::vector<py::object>>>();
403-
for (auto glyph: glyphs) {
404-
auto [prop, fontsize, c, ox, oy] = glyph
405-
.cast<std::tuple<py::object, double, std::string, double, double>>();
406-
cairo_move_to(cr_, ox, oy);
407-
cairo_select_font_face(
408-
cr_,
409-
prop.attr("name").cast<std::string>().c_str(),
410-
CAIRO_FONT_SLANT_NORMAL,
411-
CAIRO_FONT_WEIGHT_NORMAL); // FIXME
412-
cairo_set_font_size(
413-
cr_,
414-
points_to_pixels(fontsize));
415-
cairo_show_text(cr_, c.c_str());
416-
}
417-
for (auto rect: rects) {
418-
auto [ox, oy, w, h] = rect.cast<rectangle_t>();
419-
cairo_new_path(cr_);
420-
cairo_rectangle(cr_, ox, oy, w, h);
421-
cairo_set_source_rgb(cr_, 0, 0, 0);
422-
cairo_fill(cr_);
433+
.cast<std::tuple<double, double, double, double, double,
434+
py::object, py::object>>();
435+
auto im_raw = py::array_t<uint8_t, py::array::c_style>{image}.mutable_unchecked<2>();
436+
auto ni = im_raw.shape(0), nj = im_raw.shape(1);
437+
438+
// // FIXME agg parser, alpha
439+
auto stride = cairo_format_stride_for_width(CAIRO_FORMAT_A8, nj);
440+
std::unique_ptr<uint8_t[]> buf;
441+
uint8_t* ptr;
442+
if (stride == nj) {
443+
ptr = im_raw.mutable_data(0, 0); // cairo is non-const.
444+
} else {
445+
auto pix = im_raw.data(0, 0);
446+
buf = std::make_unique<uint8_t[]>(ni * stride);
447+
for (size_t i = 0; i < ni; ++i) {
448+
ptr = buf.get() + i * stride;
449+
for (size_t j = 0; j < nj; ++j) {
450+
*(ptr++) = *(pix++);
451+
}
452+
}
453+
ptr = buf.get();
423454
}
455+
auto surface = cairo_image_surface_create_for_data(
456+
ptr, CAIRO_FORMAT_A8, nj, ni, stride);
457+
458+
// FIXME agg parser, grayscale
459+
// auto stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, nj);
460+
// auto pix = im_raw.data(0, 0);
461+
// std::unique_ptr<uint8_t[]> buf{new uint8_t[ni * stride]};
462+
// for (size_t i = 0; i < ni; ++i) {
463+
// auto ptr = reinterpret_cast<uint32_t*>(buf.get() + i * stride);
464+
// for (size_t j = 0; j < nj; ++j) {
465+
// *(ptr++) = 0xff000000 + (0xff - *(pix++)) * 0x010101;
466+
// }
467+
// }
468+
// auto surface = cairo_image_surface_create_for_data(
469+
// buf.get(), CAIRO_FORMAT_ARGB32, nj, ni, stride);
470+
471+
auto pattern = cairo_pattern_create_for_surface(surface);
472+
cairo_matrix_t matrix{1, 0, 0, 1, -ox, ni - oy};
473+
cairo_pattern_set_matrix(pattern, &matrix);
474+
cairo_set_source(cr_, pattern);
475+
476+
// // FIXME Already antialiased by freetype, don't do it twice?
477+
// cairo_set_antialias(cr_, CAIRO_ANTIALIAS_NONE);
478+
479+
cairo_paint(cr_);
480+
cairo_pattern_destroy(pattern);
481+
cairo_surface_destroy(surface);
424482
} else {
425483
cairo_select_font_face(
426484
cr_,
@@ -438,10 +496,14 @@ void GraphicsContextRenderer::draw_text(
438496
std::tuple<double, double, double> GraphicsContextRenderer::get_text_width_height_descent(
439497
std::string s, py::object prop, bool ismath) {
440498
if (ismath) {
441-
auto [width, height, descent, glyphs, rects] =
499+
// auto [width, height, descent, glyphs, rects] =
500+
// py::cast(this).attr("mathtext_parser").attr("parse")(s, dpi_, prop)
501+
// .cast<std::tuple<double, double, double,
502+
// std::vector<py::object>, std::vector<py::object>>>();
503+
auto [ox, oy, width, height, descent, image, chars] =
442504
py::cast(this).attr("mathtext_parser").attr("parse")(s, dpi_, prop)
443-
.cast<std::tuple<double, double, double,
444-
std::vector<py::object>, std::vector<py::object>>>();
505+
.cast<std::tuple<double, double, double, double, double,
506+
py::object, py::object>>();
445507
return {width, height, descent};
446508
} else {
447509
cairo_save(cr_);

0 commit comments

Comments
 (0)