1
votes

I'm trying to write a program that will render Asian characters in UTF-8. When I try to render the character in a terminal or text editor environment, it renders correctly. When I try to render in cairo, I get rectangles rendered in my output (not the UTF8 character I expected).

Below is an example code that I'm running which generates a PNG file output with the rendered text. When I compile in gcc and run the code, I do not get the expected character, と, but instead get a rectangle. I am currently running the example from http://cairographics.org/tutorial/ and feeding it the special characters I want to render.

#include <math.h>
#include <stdio.h>
#include <cairo.h>

int
main (int argc, char *argv[])
{
//CODE FROM http://cairographics.org/tutorial/textextents.c
    /* Variable declarations */
    cairo_surface_t *surface;
    cairo_t *cr;
    double x, y, px, ux=1, uy=1, dashlength;
    char text[]= u8"と";
    cairo_font_extents_t fe;
    cairo_text_extents_t te;

    /* Prepare drawing area */
    surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 240, 240);
    cr = cairo_create (surface);
    /* Example is in 26.0 x 1.0 coordinate space */
    cairo_scale (cr, 240, 240);
    cairo_set_font_size (cr, 0.5);

    /* Drawing code goes here */
    cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
    cairo_select_font_face (cr, "Sans",
            CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
    cairo_font_extents (cr, &fe);

    cairo_device_to_user_distance (cr, &ux, &uy);
    if (ux > uy)
        px = ux;
    else
        px = uy;
    cairo_font_extents (cr, &fe);
    cairo_text_extents (cr, text, &te);
    x = 0.5 - te.x_bearing - te.width / 2;
    y = 0.5 - fe.descent + fe.height / 2;

    /* baseline, descent, ascent, height */
    cairo_set_line_width (cr, 4*px);
    dashlength = 9*px;
    cairo_set_dash (cr, &dashlength, 1, 0);
    cairo_set_source_rgba (cr, 0, 0.6, 0, 0.5);
    cairo_move_to (cr, x + te.x_bearing, y);
    cairo_rel_line_to (cr, te.width, 0);
    cairo_move_to (cr, x + te.x_bearing, y + fe.descent);
    cairo_rel_line_to (cr, te.width, 0);
    cairo_move_to (cr, x + te.x_bearing, y - fe.ascent);
    cairo_rel_line_to (cr, te.width, 0);
    cairo_move_to (cr, x + te.x_bearing, y - fe.height);
    cairo_rel_line_to (cr, te.width, 0);
    cairo_stroke (cr);

    /* extents: width & height */
    cairo_set_source_rgba (cr, 0, 0, 0.75, 0.5);
    cairo_set_line_width (cr, px);
    dashlength = 3*px;
    cairo_set_dash (cr, &dashlength, 1, 0);
    cairo_rectangle (cr, x + te.x_bearing, y + te.y_bearing, te.width, te.height);
    cairo_stroke (cr);

    /* text */
    cairo_move_to (cr, x, y);
    cairo_set_source_rgb (cr, 0, 0, 0);
    cairo_show_text (cr, text);

    /* bearing */
    cairo_set_dash (cr, NULL, 0, 0);
    cairo_set_line_width (cr, 2 * px);
    cairo_set_source_rgba (cr, 0, 0, 0.75, 0.5);
    cairo_move_to (cr, x, y);
    cairo_rel_line_to (cr, te.x_bearing, te.y_bearing);
    cairo_stroke (cr);

    /* text's advance */
    cairo_set_source_rgba (cr, 0, 0, 0.75, 0.5);
    cairo_arc (cr, x + te.x_advance, y + te.y_advance, 5 * px, 0, 2 * M_PI);
    cairo_fill (cr);

    /* reference point */
    cairo_arc (cr, x, y, 5 * px, 0, 2 * M_PI);
    cairo_set_source_rgba (cr, 0.75, 0, 0, 0.5);
    cairo_fill (cr);

    /* Write output and clean up */
    cairo_surface_write_to_png (surface, "textextents.png");
    cairo_destroy (cr);
    cairo_surface_destroy (surface);

    return 0;
}

I realize that characters in C++ are only 8 bits and cannot be expected to extend to the special character set I am trying to render, so to get this to work do I need to represent the special characters in a different way?

Here is the image I get when I run the code: Rendition of と

So how can I render special characters in Cairo? Do I need to use Pango instead, or is my representation in C++ fundamentally incorrect?

normal characters like 'a' and 'á' render correctly

I've managed to get some characters to render on a GtkDrawingArea widget using Pango, so this would appear to be a problem with Cairo.

1
that's a direct link to the C code. I'm updating it to show the websiteArlington
Do you have the right fonts installed?n. 1.8e9-where's-my-share m.
renders in terminal, firefox, and all my other applicationsArlington
Your C++ is correct as long as you can render other characters. Try with u8"a" to start with.Kuba hasn't forgotten Monica
You are using the cairo toy text API font rendering. For serious (ie. not basic latin text) font rendering you should use PangoCairo.rodrigo

1 Answers

1
votes

As per the Cairo documentation, it is not recommended to use Cairo for text manipulation. They describe it as a toy text API, and recommend the use of Pango for text, as you already mentioned the possibility of doing. I cannot say with certainty that this is your problem, but in the description on the linked page, it says Cairo does not handle font problems well. Your selected font may not support this character.