You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Cairo/PangoCairo中加载自定义TTF字体及相关操作?

使用Cairo/PangoCairo加载并使用自定义TTF字体

1. 加载自定义TTF字体文件

用Cairo直接加载(基于FreeType)

Cairo依赖FreeType处理字体渲染,你可以直接通过FreeType的API加载TTF文件,再封装成Cairo的字体面对象:

#include <cairo.h>
#include <cairo-ft.h>
#include <ft2build.h>
#include FT_FREETYPE_H

int load_custom_cairo_font(const char* ttf_path, cairo_font_face_t** out_face) {
    FT_Library ft_lib;
    FT_Face ft_face;
    int ret;

    // 初始化FreeType库
    if ((ret = FT_Init_FreeType(&ft_lib)) != 0) {
        return ret;
    }

    // 从磁盘加载TTF文件
    if ((ret = FT_New_Face(ft_lib, ttf_path, 0, &ft_face)) != 0) {
        FT_Done_FreeType(ft_lib);
        return ret;
    }

    // 转换为Cairo字体面,Cairo会接管FT_Face的生命周期,无需手动销毁
    *out_face = cairo_ft_font_face_create_for_ft_face(ft_face, 0);
    FT_Done_FreeType(ft_lib);
    return 0;
}

用PangoCairo加载(结合Fontconfig)

Pango默认通过Fontconfig管理字体库,你可以把自定义TTF注册到Fontconfig,让Pango能识别到:

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

void load_custom_pango_font(const char* ttf_path) {
    FcConfig* config = FcConfigGetCurrent();
    // 将字体文件添加到当前Fontconfig配置
    FcConfigAppFontAddFile(config, (FcChar8*)ttf_path);
    // 重建字体索引,让新字体生效
    FcConfigSetCurrent(config);
    FcConfigBuildFonts(config);
}

如果不想影响全局字体配置,可以创建独立的FcConfig实例,再绑定到PangoFontMap上使用。

2. 渲染时选择自定义字体

在Cairo中使用

拿到加载好的cairo_font_face_t后,直接设置到Cairo上下文即可:

cairo_t* cr = ...; // 已初始化的Cairo绘图上下文
cairo_font_face_t* custom_font = ...; // 之前加载的自定义字体面

cairo_set_font_face(cr, custom_font);
cairo_set_font_size(cr, 16.0); // 设置字体大小
cairo_move_to(cr, 10, 50); // 设置文本起始位置
cairo_show_text(cr, "这是自定义字体的文本");

在PangoCairo中使用

如果已经通过Fontconfig注册了字体,直接通过字体家族名创建PangoFontDescription即可:

cairo_t* cr = ...;
// 创建Pango布局对象,用于管理文本排版
PangoLayout* layout = pango_cairo_create_layout(cr);

// 创建字体描述,指定自定义字体的家族名(比如TTF文件中的"Custom Sans")
PangoFontDescription* desc = pango_font_description_new();
pango_font_description_set_family(desc, "Custom Sans");
pango_font_description_set_size(desc, 16 * PANGO_SCALE); // Pango使用1/1024像素的缩放单位

pango_layout_set_font_description(layout, desc);
pango_layout_set_text(layout, "用Pango渲染的自定义字体文本", -1);

// 将布局渲染到Cairo上下文
pango_cairo_show_layout(cr, layout);

// 释放资源
g_object_unref(layout);
pango_font_description_free(desc);

如果是直接从FreeType加载的字体面,也可以转成Pango字体面后绑定到上下文:

cairo_font_face_t* cairo_face = ...;
PangoFontFace* pango_face = pango_cairo_font_face_create(cairo_face);
PangoContext* ctx = pango_cairo_create_context(cr);
pango_context_set_font_face(ctx, pango_face);
// 后续用这个上下文创建布局即可

3. 支持从内存加载字体吗?

当然支持,核心是借助FreeType的FT_New_Memory_Face接口从内存块加载字体数据,再对接Cairo或Pango:

Cairo从内存加载

int load_cairo_font_from_memory(const unsigned char* font_data, size_t data_len, cairo_font_face_t** out_face) {
    FT_Library ft_lib;
    FT_Face ft_face;
    int ret;

    if ((ret = FT_Init_FreeType(&ft_lib)) != 0) {
        return ret;
    }

    // 从内存加载字体,第三个参数0表示不复制数据,需确保内存块在字体面存活期间有效
    if ((ret = FT_New_Memory_Face(ft_lib, font_data, data_len, 0, &ft_face)) != 0) {
        FT_Done_FreeType(ft_lib);
        return ret;
    }

    *out_face = cairo_ft_font_face_create_for_ft_face(ft_face, 0);
    FT_Done_FreeType(ft_lib);
    return 0;
}

PangoCairo从内存加载

可以先把内存中的字体数据添加到Fontconfig,之后用法和文件加载的字体一致:

void load_pango_font_from_memory(const unsigned char* font_data, size_t data_len) {
    FcConfig* config = FcConfigGetCurrent();
    FcPattern* pattern = FcPatternCreate();
    // 将内存字体数据封装为FcBlob并添加到配置
    FcPatternAddBlob(pattern, FC_FONTBLOB, FcMemBlobCreate(font_data, data_len, NULL, NULL));
    FcConfigAppFontAddPattern(config, pattern);
    FcPatternDestroy(pattern);
    // 重建字体索引
    FcConfigBuildFonts(config);
}

也可以像Cairo那样,先转成Cairo字体面,再包装成Pango字体面使用。


内容的提问来源于stack exchange,提问作者Maximilian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 07:20:07