В моем приложении я использую 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()
требует, чтобы поверхность уже была создана, и я не смог найти способ визуализации макета из pango_layout_new()
через Каир. API документирует одну из функций рендеринга, pango_cairo_update_layout()
укажите, что pango_cairo_create_layout()
должен был быть использован для создания макета; тем не менее, более важная функция, pango_cairo_show_layout()
, отмечает, что нет таких требований, и я не уверен, означает ли это, что любой макет Pango разрешен или нет. Хотя я мог проверить, работает ли он, я боюсь, что метод проб и ошибок может привести меня к неопределенному поведению.
Я чувствую, что застрял в ситуации с курицей и яйцом, и документация для Pango — это в основном справочник по API с небольшим объяснением того, как библиотека предназначена для использования. Есть ли способ сделать это правильно?
Я понял этот процесс. Надеюсь, информация полезна — хотя я не претендую на то, что это «правильный» способ сделать что-либо из этого, просто это работает.
Сначала настройте 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_move_to(cairoContext, 0, 0);
pango_cairo_update_layout( cairoContext, pangoLayout );
pango_cairo_show_layout( cairoContext, pangoLayout );