I am trying to predict how wide the text will appear rendered by pango library but I am trying to achieve it in bare Freetype for performance sake.
To answer the commenters - yes I measured performance with the callgrind
tool. And pango is spending most of its time in fontconfig, which is impossible to work around. The pango_layout_get_extents
is also not terribly fast. Meanwhile freetype's performance is blazingly fast - yet results inaccurate due to lack of proper settings perhaps. Unfortunately I am unable to post rendered bitmaps since I do only plain measurements - but it might be a worthwhile endeavour to implement is for comparison's sake. The rendering in my use case is done by a web browser in SVG and my only need is to predict what length the rendered text will be - hence not providing bitmaps in the question since I have no rendering code.
My test program run:
> ./freetype_text /usr/share/fonts/truetype/verdana.ttf "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW"
Width: 374
However .. the same text at font size 10 (72dpi) is rendered in pango with 340px. The measurement is by a common method of measuring the layout with:
PangoRectangle logical_rect = {0, 0};
pango_layout_get_extents (layout, NULL, &logical_rect);
What could be the reason for differences I am observing? The differences I observe range from 0%-15%.
Below is my freetype testing program (compile with gcc freetype_text.c $(pkg-config --cflags --libs freetype2))
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_OUTLINE_H
#include FT_STROKER_H
#include FT_GLYPH_H
#include FT_TRUETYPE_IDS_H
static FT_Library library;
int main(int argc, char** argv)
{
FT_Error error = FT_Init_FreeType( &library );
if ( error ) {
return 1;
}
int i;
FT_Face face;
error = FT_New_Face( library, argv[1], 0, &face );
if(error) {
return 2;
}
FT_Set_Pixel_Sizes(face, 0, 10);
char* str = argv[2];
wchar_t ch = 0;
FT_GlyphSlot slot = face->glyph;
int w = 0;
int previous = 0;
while( (ch = *str) != 0) {
int glyph_index = FT_Get_Char_Index( face, ch );
error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT|FT_LOAD_NO_BITMAP);
str++;
w += slot->advance.x;
if(previous && glyph_index )
{
FT_Vector delta;
FT_Get_Kerning( face, previous, glyph_index, FT_KERNING_DEFAULT, &delta );
w += delta.x ;
}
previous = glyph_index;
}
printf("Width: %i\n", w/64);
return 0;
}