I'm trying to build a program for a raspberry pi that prints text to a small SPI LCD screen and I want to set the font using truetype fonts and the FreeType API. When I try to set the font size I run into segmentation faults. If I don't include FT_Set_Pixel_Size
then I get errors back from FT_Load_Glyph
and other posts have linked this to not having the font size set.
#include <freetype2/ft2build.h>
#include FT_FREETYPE_H
void display_draw_text(int x, int y, const char* text) {
FT_Library lib;
FT_Face face;
int error;
error = FT_Init_FreeType (&lib);
if(error)
{
printf("Init FreeType error %d", error);
}
error = FT_New_Face (lib, FONT_FILE, 0, &face);
if(error)
{
printf("FT Face error %d", error);
}
error = FT_Set_Pixel_Sizes(
face, /* handle to face object */
(FT_UInt)0, /* char_height in 1/64 of points */
(FT_UInt)16); /* vertical device resolution */
if(error)
printf("Pixel Error %d", error);
while (*text)
{
char c = *text++;
if (c < 32 || c > 126) c = '?';
FT_UInt gi = FT_Get_Char_Index(face, c);
printf ("%d -> %04X\n", gi, c);
error = FT_Load_Glyph (face, (FT_UInt)gi, FT_LOAD_DEFAULT);
if(error != 0)
printf("Load Glyph Failed %d\n", error);
int bbox_ymax = face->bbox.yMax / 64;
int glyph_width = face->glyph->metrics.width / 64;
int advance = face->glyph->metrics.horiAdvance / 64;
int x_off = (advance - glyph_width) / 2;
int y_off = bbox_ymax - face->glyph->metrics.horiBearingY / 64;
for (int i = 0; i < (int)face->glyph->bitmap.rows; i++)
{
// row_offset is the distance from the top of the framebuffer
// of the text bounding box
int row_offset = y + i + y_off;
for (int j = 0; j < (int)face->glyph->bitmap.width; j++)
{
unsigned char p =
face->glyph->bitmap.buffer [i * face->glyph->bitmap.pitch + j];
// Don't draw a zero value, unless you want to fill the bounding
// box with black.
if (p)
{
display_draw_pixel(x + j +x_off, row_offset, COLOR_BLACK);
}
}
}
// Move the x position, ready for the next character.
x += advance;
}
}
The below line loads glyph as a vector contours. It does not rasterize the glyph image to a bitmap.
error = FT_Load_Glyph (face, (FT_UInt)gi, FT_LOAD_DEFAULT);
Therefore face->glyph->bitmap.buffer
is NULL and access to it gives segmentation fault.
You can rasterize glyph at the very load time:
FT_Load_Glyph (face, (FT_UInt)gi, FT_LOAD_RENDER);
BTW
If you will turn on warning flags for compilation, it will give you many interesting insights. Most important ones is that your code freely converts between signed unsigned type values. This will result in problems later on.