在创建 Cairo Surface 之前创建 Pango 布局

6
在我的应用程序中,我正在使用Pango和Cairo来创建文本纹理。这些纹理的宽度是固定的,但应根据文本内容自动缩放其高度。然后,涉及此情况的父对象将调整其高度以匹配文本。
问题在于,我一直以来初始化Pango和Cairo的方式不允许这样做。目前,系统的设置方式如下:
cairo_surface_t* cairoSurface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, sizeX, sizeY );
cairo_t* cairoContext = cairo_create( cairoSurface );
PangoLayout* pangoLayout = pango_cairo_create_layout( cairoContext );

这将会固定表面的高度,但我并不总是需要这样做。

我的理解是,如果未指定布局高度,则会自动缩放高度,然后可以通过 pango_layout_get_size() 找到它的高度。我想先创建布局,然后使用此函数的输出来创建表面。

然而,pango_cairo_create_layout() 要求表面已经被创建,并且我一直无法找到一种通过 Cairo 从 pango_layout_new() 渲染布局的方法。API 文档中的一个渲染函数之一 pango_cairo_update_layout() 指定了必须使用 pango_cairo_create_layout() 来创建布局; 然而,更重要的函数 pango_cairo_show_layout() 并没有注明此类要求,我不确定这是否意味着允许使用任何 Pango 布局。虽然我可以测试它是否有效,但我担心试错可能会导致未定义的行为。

我觉得自己陷入了一个鸡生蛋的境地,而 Pango 的文档大多是 API 参考,很少解释库的使用方式。有没有一种正确的方法来解决这个问题呢?

1个回答

4

我已经掌握了这个过程。希望这些信息能够帮到你,尽管我不能保证这是“正确”执行此操作的方式,但这种方法确实有效。

首先,设置FontConfig。在某些系统上可能不需要这样做 - 在Linux上自动设置可能没问题。然而,在Windows上,FontConfig会有问题。最简单的处理方法是在内存中创建一个配置文件,并将其指向你想要查找字体的位置。我将它指向我的程序资源目录。你可以使用“C:\Windows\Fonts”,但请注意这需要很长时间才能加载。加载适当的font.conf文件可能是最好的方法,但我自己的运气并不好。

gchar* workingDir = g_get_current_dir();
gchar* resourceDir = g_strjoin( NULL, workingDir, "/Resources", (char*)0 );
FcConfigAppFontAddDir( fontConfig, (const FcChar8*)resourceDir );
g_free(workingDir);
g_free(resourceDir);
FcConfigBuildFonts( fontConfig );
FcConfigSetCurrent( fontConfig );

然后,您需要创建字体映射、Pango上下文和Pango布局:
PangoFontMap* fontMap = pango_cairo_font_map_new();
PangoContext* pangoContext = pango_font_map_create_context( fontMap );
PangoLayout* pangoLayout = pango_layout_new( pangoContext );

现在,使用手动创建的布局(而非使用 pango_cairo_create_layout())似乎无法自动加载字体。尝试使用字体映射中已列出但未加载的字体会导致 Pango-Cairo 崩溃(使用根本没有列出的字体将返回默认字体)。因此,请加载字体映射中列出的所有字体:

FcPattern *p = FcPatternCreate();
FcObjectSet *os = FcObjectSetBuild(FC_FAMILY,NULL);
FcFontSet *fs = FcFontList(fontConfig, p, os);
FcPatternDestroy( p );
FcObjectSetDestroy( os );
for( int i = 0; i < fs->nfont; ++i )
{
    guchar* fontName = FcNameUnparse( fs->fonts[i] );
    PangoFontDescription* fontDesc = pango_font_description_from_string( (gchar*)fontName );
    pango_font_map_load_font( fontMap, pangoContext, fontDesc );
    pango_font_description_free( fontDesc );
    g_free(fontName);
}

指定宽度:

pango_layout_set_width( pangoLayout, sizeX * PANGO_SCALE );

在这个时候,您应该设置对齐方式/文本格式等等。

然后您可以插入您的文本:

pango_layout_set_markup( pangoLayout, text.c_str( ), -1 );

接下来,您可以通过pango_layout_get_pixel_size()获取布局高度,并使用它创建Cairo的对象。然后,您可以通过以下方式进行渲染:

cairo_move_to(cairoContext, 0, 0);
pango_cairo_update_layout( cairoContext, pangoLayout );
pango_cairo_show_layout( cairoContext, pangoLayout );

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接