使用cairo和freetype进行字体布局和渲染

7
我有一个系统,只有freetype2和cairo库可用。我想要实现的是:
- 获取UTF-8文本的字形 - 布局文本,存储位置信息(由我自己完成) - 获取每个字形的cairo路径以进行渲染
不幸的是,文档并没有真正解释应该如何完成这些操作,因为它们期望使用像Pango这样的更高级别的库。
我认为正确的方法是:使用cairo_scaled_font_create创建一个缩放字体,然后使用cairo_scaled_font_text_to_glyphs检索文本的字形。cairo_glyph_extents然后为每个字形提供范围。但是,我如何获取字距和前进等信息呢?另外,我如何为每个字体获取路径?
这个主题还有其他资源吗?这些函数是预期的方法吗?

1
你看过这个Cairo文档页面吗?我从未使用过Cairo的FreeType,所以我不知道是否关键,但如果它解决了你的问题,我可以将其发布为答案。 - oldtechaa
本页面介绍如何使用freetype字体创建cairo_font_face_t。然后,您可以使用此字体创建缩放字体。从那时起,路线就不清楚了。 - maxdev
您可以使用Cairo的文本功能来使用FreeType的cairo_font_face_t,布局文本并进行渲染。虽然不建议这样做,请参阅cairo页面以了解Pango的使用情况。但是,由于您也无法使用Pango,因此这应该是可行的。为什么机器没有其他库可用? - oldtechaa
是的,但它们大多解释了所谓的“玩具文本API” - 我想使用字形API,但找不到有关如何正确使用它以获取字形布局信息和呈现的适当信息。这是为Ghost OS(http://ghostkernel.org/)窗口管理器而设计的,我的操作系统项目;将Pango移植带来了相当多的依赖项,我不愿意移植(fontconfig ...)只是为了获得布局功能。我之前用纯freetype进行过良好的布局,所以一定有办法。 - maxdev
换句话说,您想使用FreeType创建一个FT_Bitmap,然后将位图应用于您的Cairo表面? - oldtechaa
显示剩余5条评论
2个回答

5
好的,我找到了需要的内容。
首先,您需要创建一个cairo_scaled_font_t,它代表特定大小的字体。要做到这一点,可以在设置字体后简单地使用cairo_get_scaled_font,它为上下文中当前设置创建一个缩放字体。
接下来,您可以使用cairo_scaled_font_text_to_glyphs 将输入文本转换为字形和群集数组。聚类映射表示UTF-8字符串的哪个部分属于字形数组中对应的字形。
要获取字形的扩展,使用 cairo_scaled_font_glyph_extents。它给出每个字形/一组字形的尺寸、进度和轴承。
最后,使用cairo_glyph_path将字形路径放入上下文中。这些路径可以按需绘制。
以下示例将输入字符串转换为字形、检索其范围并呈现它们:
const char* text = "Hello world";
int fontSize = 14;
cairo_font_face_t* fontFace = ...;

// get the scaled font object
cairo_set_font_face(cr, fontFace);
cairo_set_font_size(cr, fontSize);
auto scaled_face = cairo_get_scaled_font(cr);

// get glyphs for the text
cairo_glyph_t* glyphs = NULL;
int glyph_count;
cairo_text_cluster_t* clusters = NULL;
int cluster_count;
cairo_text_cluster_flags_t clusterflags;

auto stat = cairo_scaled_font_text_to_glyphs(scaled_face, 0, 0, text, strlen(text), &glyphs, &glyph_count, &clusters, &cluster_count,
        &clusterflags);

// check if conversion was successful
if (stat == CAIRO_STATUS_SUCCESS) {

    // text paints on bottom line
    cairo_translate(cr, 0, fontSize);

    // draw each cluster
    int glyph_index = 0;
    int byte_index = 0;

    for (int i = 0; i < cluster_count; i++) {
        cairo_text_cluster_t* cluster = &clusters[i];
        cairo_glyph_t* clusterglyphs = &glyphs[glyph_index];

        // get extents for the glyphs in the cluster
        cairo_text_extents_t extents;
        cairo_scaled_font_glyph_extents(scaled_face, clusterglyphs, cluster->num_glyphs, &extents);
        // ... for later use

        // put paths for current cluster to context
        cairo_glyph_path(cr, clusterglyphs, cluster->num_glyphs);

        // draw black text with green stroke
        cairo_set_source_rgba(cr, 0.2, 0.2, 0.2, 1.0);
        cairo_fill_preserve(cr);
        cairo_set_source_rgba(cr, 0, 1, 0, 1.0);
        cairo_set_line_width(cr, 0.5);
        cairo_stroke(cr);

        // glyph/byte position
        glyph_index += cluster->num_glyphs;
        byte_index += cluster->num_bytes;
    }
}

1
那些函数似乎是最佳选择,考虑到Cairo的文本系统。这只是更明显地表明Cairo并不真正适合文本。它将无法真正进行字距或路径处理。我相信Pango会有自己复杂的代码来完成这些事情。
为了Ghost的最佳发展,我建议移植Pango,因为您(或其他人)最终可能会需要它。

看见我最新的评论了吗?我希望cairo能够为我提供字形的布局信息和路径。这些信息必须存在,因为Pango依赖于它。但是我无法找到任何关于此的好的文档。问题在于,Pango需要像fontconfig和gnome库这样的东西,而我不想要在Ghost中使用这些库——它们强制我接受我不想要的设计决策,只是为了得到我的字符排版。虽然我很感谢你迄今为止的帮助,很高兴看到你的兴趣 :) - maxdev
2
我建议使用您所描述的函数。它们似乎是正确的选择。问题在于Cairo非常受限,没有字距和没有明确的方法来轻松地从字形创建路径。你几乎只能使用show_glyphsshow_text_glyphs来显示字形。现在我了解得更多了,我会编辑我的答案。 - oldtechaa
看到另一个答案了,虽然感谢你的努力!:-) - maxdev
我为你的帮助提供了赏金,所以它并没有浪费。 - maxdev
非常感谢!很抱歉我不能做更多来赢得它。很高兴你找到了解决方案。 - oldtechaa

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