使用 Harfbuzz 正确组合字符位置
Correct combining characters positions with Harfbuzz
我正在尝试使用 Harfbuzz 和带符号的距离场图集来呈现文本。
代码基本上是这样的:
void drawText(const std::wstring &str, Vec2 pos)
{
// Init harfbuzz
hb_buffer_t *hbBuf = hb_buffer_create();
hb_buffer_set_direction(hbBuf, HB_DIRECTION_LTR);
hb_buffer_set_script(hbBuf, HB_SCRIPT_LATIN);
hb_buffer_set_language(hbBuf, hb_language_from_string("en", 2));
// Process string
hb_buffer_add_utf32(hbBuf, reinterpret_cast<const uint32_t*>(str.c_str()), -1, 0, -1);
hb_shape(font.hb, hbBuf, nullptr, 0);
// Display string
unsigned int nbGlyphs;
hb_glyph_info_t *glyphInfos = hb_buffer_get_glyph_infos(hbBuf, &nbGlyphs);
hb_glyph_position_t *glyphPos = hb_buffer_get_glyph_positions(hbBuf, &nbGlyphs);
for(unsigned int i = 0; i < nbGlyphs; i++)
{
Vec2 drawPos = pos + Vec2(glyphPos[i].x_offset, glyphPos[i].y_offset) / 64.f;
drawGlyph(glyphInfos[i].codepoint, drawPos);
pos.x += glyphPos[i].x_advance / 64.f;
pos.y += glyphPos[i].y_advance / 64.f;
}
}
对于英语短语,文本看起来形状正确,但当我用变音符号测试它时,它们看起来错位了。
我正在用 aâa aâ̈a bb̂b bb̂̈b bb̧b bb͜b bb︠︡b 测试它。 Unicode 字符串不包含预组合字符。 Harfbuzz
使用预组合字符â,使这个看起来不错。大多数其他变音符号都已关闭。
Text with diacritics on the left of where they should be
当我将 x_offset 乘以 0.5 时,组合字符的位置更好。重音符和变音符位于正确的 x 位置。重音不堆叠并且在 b 上太低。 BBB (U+035C) 下的弧应该连接最后两个字母,而不是以第二个 b 为中心。
上一组b我也试过U+FE20和U+FE21。我测试U+FE21是2号b,不过看起来应该是3号。
Test with glyphPos[i].x_offset * 0.5f, better but still wrong
我尝试了几种字体,但在这些字体中,只有 NotoSansDisplay-Regular.ttf 具有组合字符。我没有设法让程序在我的 Debian 系统上按预期显示该字符串(测试,使用 HarfBuzz 2.6.4-1)。
使用Windows,我得到了更好的结果。这是我所期望的:重音是堆叠的,它下面的组合双短音符在正确的位置,cedilla 已关闭。
Text rendering closer to what I expect
我是不是在使用 HarfBuzz 做错了什么,或者我正在测试 HarfBuzz 支持的小众案例?
编辑:
实际问题不是上面描述的。
我用 FreeType FT_New_Face
加载了一个字体,然后用 hb_ft_font_create 创建了一个 hb_font_t
。
对于绘制的每个字符串,我都调用了 FT_Set_Pixel_Sizes
但保留了 hb_font_t
.
您应该尝试使用 hb-view / hb-shape 塑造相同的文本和字体。这将帮助您缩小问题所在的范围。我胡乱猜测问题出在你如何/是否在你的图谱中解释字形来源。
每次使用 FT_Set_Pixel_Sizes
更改字体大小时,使用 hb_ft_font_create
创建一个新的 hb_font_t
。
我正在尝试使用 Harfbuzz 和带符号的距离场图集来呈现文本。
代码基本上是这样的:
void drawText(const std::wstring &str, Vec2 pos)
{
// Init harfbuzz
hb_buffer_t *hbBuf = hb_buffer_create();
hb_buffer_set_direction(hbBuf, HB_DIRECTION_LTR);
hb_buffer_set_script(hbBuf, HB_SCRIPT_LATIN);
hb_buffer_set_language(hbBuf, hb_language_from_string("en", 2));
// Process string
hb_buffer_add_utf32(hbBuf, reinterpret_cast<const uint32_t*>(str.c_str()), -1, 0, -1);
hb_shape(font.hb, hbBuf, nullptr, 0);
// Display string
unsigned int nbGlyphs;
hb_glyph_info_t *glyphInfos = hb_buffer_get_glyph_infos(hbBuf, &nbGlyphs);
hb_glyph_position_t *glyphPos = hb_buffer_get_glyph_positions(hbBuf, &nbGlyphs);
for(unsigned int i = 0; i < nbGlyphs; i++)
{
Vec2 drawPos = pos + Vec2(glyphPos[i].x_offset, glyphPos[i].y_offset) / 64.f;
drawGlyph(glyphInfos[i].codepoint, drawPos);
pos.x += glyphPos[i].x_advance / 64.f;
pos.y += glyphPos[i].y_advance / 64.f;
}
}
对于英语短语,文本看起来形状正确,但当我用变音符号测试它时,它们看起来错位了。
我正在用 aâa aâ̈a bb̂b bb̂̈b bb̧b bb͜b bb︠︡b 测试它。 Unicode 字符串不包含预组合字符。 Harfbuzz
使用预组合字符â,使这个看起来不错。大多数其他变音符号都已关闭。
Text with diacritics on the left of where they should be
当我将 x_offset 乘以 0.5 时,组合字符的位置更好。重音符和变音符位于正确的 x 位置。重音不堆叠并且在 b 上太低。 BBB (U+035C) 下的弧应该连接最后两个字母,而不是以第二个 b 为中心。
上一组b我也试过U+FE20和U+FE21。我测试U+FE21是2号b,不过看起来应该是3号。
Test with glyphPos[i].x_offset * 0.5f, better but still wrong
我尝试了几种字体,但在这些字体中,只有 NotoSansDisplay-Regular.ttf 具有组合字符。我没有设法让程序在我的 Debian 系统上按预期显示该字符串(测试,使用 HarfBuzz 2.6.4-1)。
使用Windows,我得到了更好的结果。这是我所期望的:重音是堆叠的,它下面的组合双短音符在正确的位置,cedilla 已关闭。
Text rendering closer to what I expect
我是不是在使用 HarfBuzz 做错了什么,或者我正在测试 HarfBuzz 支持的小众案例?
编辑:
实际问题不是上面描述的。
我用 FreeType FT_New_Face
加载了一个字体,然后用 hb_ft_font_create 创建了一个 hb_font_t
。
对于绘制的每个字符串,我都调用了 FT_Set_Pixel_Sizes
但保留了 hb_font_t
.
您应该尝试使用 hb-view / hb-shape 塑造相同的文本和字体。这将帮助您缩小问题所在的范围。我胡乱猜测问题出在你如何/是否在你的图谱中解释字形来源。
每次使用 FT_Set_Pixel_Sizes
更改字体大小时,使用 hb_ft_font_create
创建一个新的 hb_font_t
。