如何在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
相关产品推荐
相关产品推荐

