@@ -199,9 +199,10 @@ void GraphicsContextRenderer::set_linewidth(double lw) {
199
199
200
200
rgb_t GraphicsContextRenderer::get_rgb (void ) {
201
201
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)});
205
206
}
206
207
return {r, g, b};
207
208
}
@@ -261,10 +262,12 @@ void GraphicsContextRenderer::draw_image(
261
262
if (im_raw.shape (2 ) != 4 ) {
262
263
throw std::invalid_argument (" RGBA array must have size (m, n, 4)" );
263
264
}
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]};
266
268
if (alpha_) {
267
269
for (size_t i = 0 ; i < ni; ++i) {
270
+ auto ptr = reinterpret_cast <uint32_t *>(buf.get () + i * stride);
268
271
for (size_t j = 0 ; j < nj; ++j) {
269
272
auto pix = im_raw.data (i, j, 0 );
270
273
auto r = *(pix++), g = *(pix++), b = *(pix++), a = *(pix++);
@@ -275,6 +278,7 @@ void GraphicsContextRenderer::draw_image(
275
278
}
276
279
} else {
277
280
for (size_t i = 0 ; i < ni; ++i) {
281
+ auto ptr = reinterpret_cast <uint32_t *>(buf.get () + i * stride);
278
282
for (size_t j = 0 ; j < nj; ++j) {
279
283
auto pix = im_raw.data (i, j, 0 );
280
284
auto r = *(pix++), g = *(pix++), b = *(pix++), a = *(pix++);
@@ -285,8 +289,7 @@ void GraphicsContextRenderer::draw_image(
285
289
}
286
290
}
287
291
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);
290
293
auto pattern = cairo_pattern_create_for_surface (surface);
291
294
cairo_matrix_t matrix{1 , 0 , 0 , -1 , -x, -y + get_height ()};
292
295
cairo_pattern_set_matrix (pattern, &matrix);
@@ -393,34 +396,89 @@ void GraphicsContextRenderer::draw_text(
393
396
return ;
394
397
}
395
398
cairo_save (cr_);
396
- cairo_translate (cr_, x, y );
399
+ cairo_translate (cr_, int (x), int (y) );
397
400
cairo_rotate (cr_, -angle * M_PI / 180 );
398
401
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] =
400
432
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 ();
423
454
}
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);
424
482
} else {
425
483
cairo_select_font_face (
426
484
cr_,
@@ -438,10 +496,14 @@ void GraphicsContextRenderer::draw_text(
438
496
std::tuple<double , double , double > GraphicsContextRenderer::get_text_width_height_descent (
439
497
std::string s, py::object prop, bool ismath) {
440
498
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] =
442
504
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>>();
445
507
return {width, height, descent};
446
508
} else {
447
509
cairo_save (cr_);
0 commit comments