You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

树莓派SPI LCD文本显示开发中FreeType的FT_Set_Pixel_Size触发段错误问题求助

树莓派SPI LCD文本显示开发中FreeType的FT_Set_Pixel_Size触发段错误问题求助

你好,我看了你的代码和问题描述,大概率是错误处理不完整导致的空指针访问,这也是FreeType开发中很容易踩的坑,下面给你详细分析并给出修复方案:

核心问题原因

你的代码里存在两个致命的逻辑漏洞:

  1. 当FT_Init_FreeType或FT_New_Face调用失败时,程序没有终止后续操作,而是继续执行。比如如果FONT_FILE路径错误、字体文件不存在或无权限,FT_New_Face会返回错误码,此时face是空指针,后续调用FT_Set_Pixel_Size(face, ...)直接访问空指针,必然触发段错误。
  2. 即使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定位具体问题:

  1. 编译时添加-g参数开启调试信息:gcc your_code.c -o your_program -g -lfreetype
  2. 启动gdb调试:gdb ./your_program
  3. 执行程序:run
  4. 触发段错后输入bt查看栈回溯,即可看到出错的具体代码行。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 09:33:02