Feb 09, 2026
2 min read
ESP32,
Rust,
C,
Embedded Systems,

在嵌入式 Rust 中显示中文字符的方法

本文介绍了如何在资源受限的嵌入式环境中显示中文字符,特别是使用 embedded-graphics 库的方法。由于该库默认不支持中文字符,文章详细说明了如何使用 BDF 字体格式和 eg-bdf 工具来生成和使用中文字库,并提供了具体的代码示例和解决方案。

由于嵌入式场景的资源有限,通常默认的显示库只支持英文和数字以及少量的字符显示,并不支持中文字符。比如 embedded-graphics 内置的所有字符集里就不支持中文字符的显示。

因此我们需要自己生成中文字符的显示库。这个库可以生成embedded-graphics 支持的中文字符集。

https://github.com/embedded-graphics/bdf

生成之前,需要把open-type 格式的中文字符集文件转换为 bdf 格式。可以使用 otf2bdf 工具来完成这个转换。

sudo apt install otf2bdf
#or
brew install otf2bdf

生成的 api 类似下面这样:


fn main() {
    let font = FontConverter::new("Regular.bdf", "REGULAR_FONT")
        //.glyphs('a'..='z')
        .glyphs('\u{0000}'..='\u{007F}') // ASCII
        .glyphs('\u{4E00}'..='\u{9FFF}') // 常用中文字体范围
        .glyphs('\u{2E80}'..='\u{2EF3}') // 常见繁体字范围
        .missing_glyph_substitute('?') // 替代字符
        .convert_eg_bdf()
        .unwrap();
 let font: MonoFontOutput = converter.convert_mono_font()?;
   font.save_png(png)?;
}

如果显示的字符非常的固定并且有限,我们完全可以手动指定要包含的中文字符。比如我生成用于显示温湿度计的字库时,我只需要这些字符:

温,湿,度,0,1,2,3,4,5,6,7,8,9,C,°,:,%

直接指定就好:

converter.glyphs(&['温','湿','度','0','1','2','3','4', '5', '6', '7', '8', '9','C','°',':',',' ,'%',' '][..]);

类似命令:

cargo run -r --bin eg-font-converter  ./vivosans.bdf REGULAR_FONT --rust font.rs  --data regular_font.data

复制上面生成的这两个文件到项目中就可以使用了。

不过上面这种方式生成的中文和英文的字符间距非常的大,不好看。

IMG_20260209_221127

bdf 项目还提供了eg-bdf 格式,这个格式显示中文是正常的。因此我修改了原有的生成命令,添加了 --convert-type 参数:

match args.convert_type {
        ConvertType::EgBdf => {
            let font: EgBdfOutput = converter.convert_eg_bdf()?;

            if let Some(rust) = &args.rust {
                std::fs::write(rust, font.rust())
                    .with_context(|| format!("Failed to write Rust file {}", rust.to_string_lossy()))?;
            }

            if let Some(data) = &args.data {
                std::fs::write(data, font.data())
                    .with_context(|| format!("Failed to write data file {}", data.to_string_lossy()))?;
            }

            // eg-bdf 使用 save 方法
            font.save("./output")?;
        }
        ConvertType::MonoFont => {
            let font: MonoFontOutput = converter.convert_mono_font()?;

            if let Some(rust) = &args.rust {
                std::fs::write(rust, font.rust())
                    .with_context(|| format!("Failed to write Rust file {}", rust.to_string_lossy()))?;
            }

            if let Some(data) = &args.data {
                std::fs::write(data, font.data())
                    .with_context(|| format!("Failed to write data file {}", data.to_string_lossy()))?;
            }

            if let Some(png) = &args.png {
                font.save_png(png)?;
            }
        }
    }
cargo run -r --bin eg-font-converter  \
    ./vivosans.bdf REGULAR_FONT  \
    --glyph-list 温,湿,度,0,1,2,3,4,5,6,7,8,9,C,°,:,% \
    --convert-type eg-bdf

同样地生成的文件丢回项目中,并把bdf 项目里的eg-bdf crate(此crate 并未发布到crates.io)添加到项目的Cargo.toml 中。

直接使用如下:

let temp_str = alloc::format!("温度:{}°C", temp);
let hum_str = alloc::format!("湿度:{}%", hum);
let temp_character_style = BdfTextStyle::new(&REGULAR_FONT, Rgb565::new(31, 41, 0)); // White
let hum_character_style = BdfTextStyle::new(&REGULAR_FONT, Rgb565::new(0, 63, 31)); // White

效果显示如下:

IMG_20260209_225748