@@ -25,7 +25,9 @@ struct GraphicsContextRenderer {
25
25
double dpi_;
26
26
std::optional<double > alpha_;
27
27
28
+ // Not exposed.
28
29
double points_to_pixels (double points);
30
+ rgba_t get_rgba (void );
29
31
30
32
GraphicsContextRenderer (double dpi);
31
33
~GraphicsContextRenderer ();
@@ -82,6 +84,19 @@ double GraphicsContextRenderer::points_to_pixels(double points) {
82
84
return points * dpi_ / 72 ;
83
85
}
84
86
87
+ rgba_t GraphicsContextRenderer::get_rgba (void ) {
88
+ double r, g, b, a;
89
+ auto status = cairo_pattern_get_rgba (cairo_get_source (cr_), &r, &g, &b, &a);
90
+ if (status != CAIRO_STATUS_SUCCESS) {
91
+ throw std::runtime_error (" Could not retrieve color from pattern: "
92
+ + std::string{cairo_status_to_string (status)});
93
+ }
94
+ if (alpha_) {
95
+ a = *alpha_;
96
+ }
97
+ return {r, g, b, a};
98
+ }
99
+
85
100
int GraphicsContextRenderer::get_width (void ) {
86
101
if (!cr_) {
87
102
return 0 ;
@@ -198,12 +213,7 @@ void GraphicsContextRenderer::set_linewidth(double lw) {
198
213
}
199
214
200
215
rgb_t GraphicsContextRenderer::get_rgb (void ) {
201
- double r, g, b, a;
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)});
206
- }
216
+ auto [r, g, b, a] = get_rgba ();
207
217
return {r, g, b};
208
218
}
209
219
@@ -396,86 +406,44 @@ void GraphicsContextRenderer::draw_text(
396
406
return ;
397
407
}
398
408
cairo_save (cr_);
399
- cairo_translate (cr_, int (x), int (y));
400
- cairo_rotate (cr_, -angle * M_PI / 180 );
409
+ // FIXME If angle == 0, we need to round x and y to avoid additional
410
+ // aliasing on top of the one already provided by freetype. Perhaps we
411
+ // should let it know about the destination subpixel position?
412
+ // If angle != 0, all hope is lost anyways.
413
+ if (angle) {
414
+ cairo_translate (cr_, x, y);
415
+ cairo_rotate (cr_, -angle * M_PI / 180 );
416
+ } else {
417
+ cairo_translate (cr_, round (x), round (y));
418
+ }
401
419
if (ismath) {
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
420
auto [ox, oy, width, height, descent, image, chars] =
432
421
py::cast (this ).attr (" mathtext_parser" ).attr (" parse" )(s, dpi_, prop)
433
422
.cast <std::tuple<double , double , double , double , double ,
434
423
py::object, py::object>>();
435
424
auto im_raw = py::array_t <uint8_t , py::array::c_style>{image}.mutable_unchecked <2 >();
436
425
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
- }
426
+ // Recompute the colors. Trying to use an A8 image seems just as
427
+ // complicated (http://cairo.cairographics.narkive.com/ijgxr19T/alpha-masks).
428
+ auto stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, nj);
429
+ auto pix = im_raw.data (0 , 0 );
430
+ std::unique_ptr<uint8_t []> buf{new uint8_t [ni * stride]};
431
+ auto [r, g, b, a] = get_rgba ();
432
+ for (size_t i = 0 ; i < ni; ++i) {
433
+ auto ptr = reinterpret_cast <uint32_t *>(buf.get () + i * stride);
434
+ for (size_t j = 0 ; j < nj; ++j) {
435
+ auto val = *(pix++);
436
+ *(ptr++) =
437
+ (uint8_t (a * val) << 24 ) + (uint8_t (a * val * r) << 16 )
438
+ + (uint8_t (a * val * g) << 8 ) + (uint8_t (a * val * b));
452
439
}
453
- ptr = buf.get ();
454
440
}
455
441
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
-
442
+ buf.get (), CAIRO_FORMAT_ARGB32, nj, ni, stride);
471
443
auto pattern = cairo_pattern_create_for_surface (surface);
472
444
cairo_matrix_t matrix{1 , 0 , 0 , 1 , -ox, ni - oy};
473
445
cairo_pattern_set_matrix (pattern, &matrix);
474
446
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
447
cairo_paint (cr_);
480
448
cairo_pattern_destroy (pattern);
481
449
cairo_surface_destroy (surface);
0 commit comments