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

STB TrueType加载Arial字体后除首字符外显示失真问题

解决STB TrueType字体渲染字符扭曲问题

我一眼就看到了几个关键问题,正是它们导致了你除第一个字符外其他字符扭曲的情况,咱们一个个来解决:

1. STB临时缓冲区被复用覆盖

stbtt_GetCodepointBitmap返回的是STB内部的静态临时缓冲区指针,每次调用这个函数都会覆盖这块内存里的内容。你现在的代码里,所有字符的memory字段都指向同一个地址,后面的字符生成时会直接覆盖前面的,最后只有最后一个字符的数据是对的,前面的全被冲掉了——这就是你看到第一个字符暂时正常,后面全扭曲的核心原因。

修复方法:每次获取到STB返回的bitmap后,把数据复制到自己分配的内存里,而不是直接存指针:

for (int i = 0; i < 52; i++) {
    int width, height;
    // 先获取bitmap数据(临时缓冲区)
    unsigned char* temp_bitmap = stbtt_GetCodepointBitmap(&font, 0, stbtt_ScaleForPixelHeight(&font, size), alphabet[i], &width, &height, 0, 0);
    if (temp_bitmap) {
        // 分配自己的内存存储该字符的bitmap
        current_character->memory = (unsigned char*)malloc(width * height);
        memcpy(current_character->memory, temp_bitmap, width * height);
        current_character->width = width;
        current_character->height = height;
    } else {
        // 处理获取失败的情况,比如设为空指针和0宽高
        current_character->memory = NULL;
        current_character->width = current_character->height = 0;
    }
    current_character++;
}

2. 渲染时使用统一宽高导致越界

你的test_render_text函数里,用第一个字符的width和height去渲染第42个字符,这完全不对——每个字符的宽高是不一样的(比如i和w的宽度差很多)。这样会导致你读取超出目标字符bitmap范围的内存,出现扭曲乱码。

修复方法:渲染哪个字符就用哪个字符的宽高:

void test_render_text(offscreen_buffer* buffer, font_buffer* font_bitmaps) {
    // 要渲染的是第42个字符,先拿到它的bitmap数据和宽高
    character_bitmap* char_to_render = &font_bitmaps->memory[42];
    if (!char_to_render->memory) return; // 空指针保护
    
    int width = char_to_render->width;
    int height = char_to_render->height;
    unsigned char* dest_row = (unsigned char*)buffer->memory;
    unsigned char* source = char_to_render->memory;
    
    for (int y = 0; y < height; y++) {
        unsigned int* dest_pixel = (unsigned int*)dest_row;
        for (int x = 0; x < width; x++) {
            unsigned char alpha = *source;
            *dest_pixel = ((alpha << 24) | (alpha << 16) | (alpha << 8) | alpha);
            dest_pixel++;
            source++;
        }
        dest_row += buffer->pitch;
    }
}

3. 额外的健壮性问题(必须修复,否则可能触发其他崩溃)

  • 文件读取未做错误检查:你直接fopen然后fread,如果文件路径不对(比如64位系统可能字体路径不同,或者文件不存在),fopen返回NULL,fread会往空指针里写数据,直接崩溃。要加上检查:
FILE* font_file = fopen("c:/windows/fonts/arialbd.ttf", "rb");
if (!font_file) {
    // 处理文件打开失败的情况,比如打印错误提示
    free(ttf_buffer);
    return;
}
size_t bytes_read = fread(ttf_buffer, 1, 1 << 25, font_file);
fclose(font_file); // 别忘了关闭文件!你之前没关,会导致资源泄漏
if (bytes_read == 0) {
    // 处理读取失败的情况
    free(ttf_buffer);
    return;
}
  • 内存泄漏问题:原来的代码里,font_bitmaps.memory被free时,每个字符的memory(如果是自己分配的)没有被释放,要在free(font_bitmaps.memory)前循环释放每个字符的内存:
if (font_bitmaps.memory) {
    for (int i = 0; i < 52; i++) {
        if (font_bitmaps.memory[i].memory) {
            free(font_bitmaps.memory[i].memory);
        }
    }
    free(font_bitmaps.memory);
}

把这些修改做完,你的字符渲染应该就能正常工作了。

内容的提问来源于stack exchange,提问作者Jackson Lenhart

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:22:37