ccairopangopangocairo

Change letter spacing in pango/cairo


I want to put more spaces between letters in text in Cairo. Cairo doesn't seem to have a native implementation for changing inter-letter spacing.

It seems like Pango should be a natural fit. However, there don't seem to be many examples of working with pangocairo on the web, and the Pango documentation is fairly concise.

Here is a minimal working example to show what I have working so far:

#include <cairo.h>
#include <pango/pangocairo.h>

int main(int argc, char **argv) {
    cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_RGBA128F, 512.0, 128.0);
    cairo_t *ctx = cairo_create(s);
    cairo_set_source_rgb(ctx, 1, 1, 1);
    cairo_paint(ctx);

    cairo_set_source_rgb(ctx, 0.0, 0.0, 0.0);
    PangoLayout *layout = pango_cairo_create_layout(ctx);
    pango_layout_set_text(layout, "Hello world", -1);

    PangoFontDescription *desc = pango_font_description_from_string("Times New Roman");
    pango_font_description_set_size(desc, 32*PANGO_SCALE);
    pango_layout_set_font_description(layout, desc);
    pango_font_description_free(desc);

    pango_cairo_update_layout(ctx, layout);
    cairo_move_to(ctx, 32.0, 32.0);
    pango_cairo_show_layout(ctx, layout);
    g_object_unref(layout);

    cairo_surface_write_to_png(s, "helloworld.png");
    cairo_destroy(ctx);
    cairo_surface_destroy(s);
}

Compile with

gcc -o helloworld `pkg-config --cflags --libs cairo pangocairo pango` helloworld.c

Then generate the final png with helloworld.

Output:

hello world

What should I add or change in my code to increase the inter-letter spacing in the image? I have a feeling attributes or attribute lists are involved, but it isn't clear what is the correct way to work with them when the goal is simply to modify this one attribute for the whole string.


Solution

  • I turned the comment from https://stackoverflow.com/users/8339821/user14063792468 into a modification of your example program. Just replace pango_layout_set_text(layout, "Hello world", -1); with pango_layout_set_markup(layout, "Hello <span letter_spacing=\"10240\" underline=\"low\">world</span>!", -1);. Why markup? Just because.

    #include <cairo.h>
    #include <pango/pangocairo.h>
    
    int main(int argc, char **argv) {
        cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_RGBA128F, 512.0, 128.0);
        cairo_t *ctx = cairo_create(s);
        cairo_set_source_rgb(ctx, 1, 1, 1);
        cairo_paint(ctx);
    
        cairo_set_source_rgb(ctx, 0.0, 0.0, 0.0);
        PangoLayout *layout = pango_cairo_create_layout(ctx);
        pango_layout_set_markup(layout, "Hello <span letter_spacing=\"10240\" underline=\"low\">world</span>!", -1);
    
        PangoFontDescription *desc = pango_font_description_from_string("Times New Roman");
        pango_font_description_set_size(desc, 32*PANGO_SCALE);
        pango_layout_set_font_description(layout, desc);
        pango_font_description_free(desc);
    
        pango_cairo_update_layout(ctx, layout);
        cairo_move_to(ctx, 32.0, 32.0);
        pango_cairo_show_layout(ctx, layout);
        g_object_unref(layout);
    
        cairo_surface_write_to_png(s, "helloworld.png");
        cairo_destroy(ctx);
        cairo_surface_destroy(s);
    }
    

    Program output

    1024 is PANGO_SCALE, is Pango's scaling unit. So e.g. 0.5 is represented by 1024/2 for Pango.