树莓派SPI LCD文本显示开发中FreeType的FT_Set_Pixel_Size触发段错误问题求助
树莓派SPI LCD文本显示开发中FreeType的FT_Set_Pixel_Size触发段错误问题求助
你好,我看了你的代码和问题描述,大概率是错误处理不完整导致的空指针访问,这也是FreeType开发中很容易踩的坑,下面给你详细分析并给出修复方案:
核心问题原因
你的代码里存在两个致命的逻辑漏洞:
- 当
FT_Init_FreeType或FT_New_Face调用失败时,程序没有终止后续操作,而是继续执行。比如如果FONT_FILE路径错误、字体文件不存在或无权限,FT_New_Face会返回错误码,此时face是空指针,后续调用FT_Set_Pixel_Size(face, ...)直接访问空指针,必然触发段错误。 - 即使
FT_New_Face成功,若FT_Load_Glyph失败后仍去访问face->glyph->metrics等成员,也会因glyph对象未初始化导致非法内存访问。
修复步骤及优化建议
1. 完善错误处理,失败后立即终止并释放资源
任何FreeType API调用失败后,必须停止后续逻辑,避免操作无效指针,同时要按顺序释放已申请的资源(先销毁Face,再销毁FreeType库)。
2. 验证字体文件路径有效性
确保FONT_FILE指向树莓派上真实存在的TrueType字体文件,建议用绝对路径(比如"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"),并确认程序有读取该文件的权限。
3. 修正参数注释(避免概念混淆)
你代码里对FT_Set_Pixel_Size的参数注释有误:该函数的第二个参数是像素宽度(传0表示自适应高度),第三个参数是像素高度,而不是你写的“1/64 of points”——后者是FT_Set_Char_Size的参数逻辑,你的参数值(0,16)是正确的。
4. 修复资源泄漏问题
原代码每次调用display_draw_text都会重复初始化FreeType库、创建Face对象,却从不销毁,多次调用会耗尽系统资源,必须在函数末尾添加资源释放逻辑。
修复后的完整代码示例
#include <freetype2/ft2build.h> #include FT_FREETYPE_H #include <stdio.h> // 请替换为你的实际字体文件路径 #define FONT_FILE "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf" #define COLOR_BLACK 0x000000 // 你的LCD像素绘制函数(保持原有实现即可) void display_draw_pixel(int x, int y, unsigned int color); void display_draw_text(int x, int y, const char* text) { FT_Library lib = NULL; FT_Face face = NULL; int error; // 初始化FreeType库 error = FT_Init_FreeType(&lib); if (error) { printf("FreeType初始化失败:错误码%d\n", error); goto cleanup; } // 创建字体Face对象 error = FT_New_Face(lib, FONT_FILE, 0, &face); if (error) { printf("创建字体Face失败:错误码%d\n", error); goto cleanup; } // 设置字体像素大小(宽度自适应,高度16像素) error = FT_Set_Pixel_Sizes(face, 0, 16); if (error) { printf("设置像素大小失败:错误码%d\n", error); goto cleanup; } while (*text) { char c = *text++; // 过滤不可打印字符,替换为问号 if (c < 32 || c > 126) c = '?'; FT_UInt glyph_index = FT_Get_Char_Index(face, c); printf("字符%c(0x%04X)的字形索引:%d\n", c, c, glyph_index); // 加载字形 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); if (error != 0) { printf("加载字形失败:错误码%d\n", error); continue; } // 将字形渲染为位图(必须执行此步骤才能访问bitmap数据) error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL); if (error != 0) { printf("渲染字形失败:错误码%d\n", error); continue; } // 计算字形排版参数(FreeType metrics单位为1/64像素,需除以64转换为实际像素) FT_GlyphSlot glyph = face->glyph; int bbox_ymax = face->bbox.yMax / 64; int glyph_width = glyph->metrics.width / 64; int advance = glyph->metrics.horiAdvance / 64; int x_offset = (advance - glyph_width) / 2; int y_offset = bbox_ymax - glyph->metrics.horiBearingY / 64; // 绘制字形位图到LCD for (int i = 0; i < (int)glyph->bitmap.rows; i++) { int row_pos = y + i + y_offset; for (int j = 0; j < (int)glyph->bitmap.width; j++) { unsigned char pixel_alpha = glyph->bitmap.buffer[i * glyph->bitmap.pitch + j]; // 只绘制非透明像素 if (pixel_alpha > 0) { display_draw_pixel(x + j + x_offset, row_pos, COLOR_BLACK); } } } // 移动到下一个字符的起始位置 x += advance; } cleanup: // 按顺序释放资源:先销毁Face,再销毁FreeType库 if (face != NULL) FT_Done_Face(face); if (lib != NULL) FT_Done_FreeType(lib); }
额外调试技巧
如果修复后仍有段错,可用gdb定位具体问题:
- 编译时添加
-g参数开启调试信息:gcc your_code.c -o your_program -g -lfreetype - 启动gdb调试:
gdb ./your_program - 执行程序:
run - 触发段错后输入
bt查看栈回溯,即可看到出错的具体代码行。
内容来源于stack exchange
相关产品推荐
相关产品推荐

