Loading a font from a file to pango?

纵饮孤独 提交于 2021-02-20 11:22:40


I have a code uses Cairo and Pango to create an image :


#define IMAGE_WIDTH  650
#define IMAGE_HEIGHT 150

#define FONT "MizuFontAlphabet Normal 40"

 * $ gcc $(pkg-config pangocairo cairo --cflags --libs) file.c

int main(int argc , char** argv) {

    cairo_surface_t *surface;
    cairo_t *cr;

    PangoLayout *layout;
    PangoFontDescription *desc;
    PangoRectangle extents;

    surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, IMAGE_WIDTH, IMAGE_HEIGHT);
    cr      = cairo_create(surface);

    cairo_rectangle(cr, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
    cairo_set_source_rgb(cr, 0, 0, 0);

    /* the font is needed to be installed in fonts directory */
    layout  = pango_cairo_create_layout(cr);
    pango_layout_set_text(layout, TEXT, -1);
    desc    = pango_font_description_from_string(FONT);
    pango_layout_set_font_description(layout, desc);
    pango_font_description_free (desc);

    pango_layout_get_pixel_extents(layout, NULL, &extents);
    int x   = (int) (IMAGE_WIDTH - extents.width) / 2;
    int y   = (int) (IMAGE_HEIGHT - extents.height) / 2;

    cairo_set_source_rgb(cr, 0.33, 0.55, 0.88);
    cairo_move_to(cr, x, y);
    pango_cairo_show_layout(cr, layout);


    cairo_surface_write_to_png(surface, "image.png");



The font I use , MizuFontAlphabet, is a none-standard font so it is needed to be installed in the fonts directory so I can use it with Pango :

    desc    = pango_font_description_from_string(FONT);

How could I load the font from a file in case that font wasn't installed?


This problem can be solved fairly easily by adding a custom font to the local fontconfig state:

#include <fontconfig/fontconfig.h>

std::string yourFontFilePath = "/home/testUser/bla.ttf";
const FcChar8 * file = (const FcChar8 *)yourFontFilePath.c_str();
FcBool fontAddStatus = FcConfigAppFontAddFile(FcConfigGetCurrent(), file);

Now the pango rendering engine will use your custom font just by using the PangoFontDescription.


You'll need Freetype to do that.

You may want to have a look at the following (GPL licensed) code from the fontview library.

Especially, the function font_model_new:

GObject *font_model_new (gchar *fontfile) {
    FontModel *model;
    FT_Library library;
    FT_Face face;
    FcConfig *config;
    TT_OS2* os2;

    g_return_val_if_fail (fontfile, NULL);

    if (FT_Init_FreeType(&library)) {
        g_error ("FT_Init_FreeType failed");
        return NULL;

    if (FT_New_Face (library, fontfile, 0, &face)) {
        g_error ("FT_New_Face failed");
        return NULL;

    if (!FT_IS_SFNT(face)) {
        g_error ("Not an SFNT font!");
        return NULL;

    config = FcConfigCreate ();
    if (!FcConfigAppFontAddFile (config, (FcChar8*)fontfile)) {
        g_error ("FcConfigAppFontAddFile failed");
        return NULL;

    model = g_object_new (FONT_MODEL_TYPE, NULL);
    model->file = g_strdup (fontfile);
    model->ft_face = face;
    model->config = config;
    model->family = face->family_name;
    model->style = face->style_name;
    model->units_per_em = face->units_per_EM;

    model->xheight = 0;
    model->ascender = 0;
    model->descender = 0;

    model->sample = NULL;

    memset(&model->color, 0, sizeof (ColorTable));

    /* Get font metadata if available/applicable */
    os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
    if (os2) {
        model->xheight = os2->sxHeight;
        model->ascender = os2->sTypoAscender;
        model->descender = os2->sTypoDescender;

    model->family = get_font_name (face, TT_NAME_ID_PREFERRED_FAMILY);
    if (!model->family)
        model->family = get_font_name (face, TT_NAME_ID_FONT_FAMILY);

    model->style = get_font_name (face, TT_NAME_ID_PREFERRED_SUBFAMILY);
    if (!model->style)
        model->style = get_font_name (face, TT_NAME_ID_FONT_SUBFAMILY);

    model->copyright = get_font_name (face, TT_NAME_ID_COPYRIGHT);
    model->version = get_font_name (face, TT_NAME_ID_VERSION_STRING);
    model->description = get_font_name (face, TT_NAME_ID_DESCRIPTION);
    model->sample = get_font_name (face, TT_NAME_ID_SAMPLE_TEXT);

    model->mmvar = NULL;
    model->mmcoords = NULL;
    if (FT_HAS_MULTIPLE_MASTERS (face)) {
        if (FT_Get_MM_Var (face, &model->mmvar) != 0) {
            model->mmvar = NULL;

    load_color_table (model);

    return G_OBJECT (model);