Rust 驱动 LCD - 显示中英文

Posted on Mon, Sep 2, 2024 Rust 单片机

embedded-graphics 支持 BDF 和 MonoFont 字体:

The draw method for text drawables returns the position of the next character. This can be used to combine text with different character styles on a single line of text.

// https://docs.rs/embedded-graphics/latest/embedded_graphics/text/index.html#examples
// Create a small and a large character style.
let small_style = MonoTextStyle::new(&FONT_6X10, Rgb565::WHITE);
let large_style = MonoTextStyle::new(&FONT_10X20, Rgb565::WHITE);

// Draw the first text at (20, 30) using the small character style.
let next = Text::new("small ", Point::new(20, 30), small_style).draw(&mut display)?;

// Draw the second text after the first text using the large character style.
let next = Text::new("large", next, large_style).draw(&mut display)?;

字体参考:https://github.com/olikraus/u8g2

1 embedded-graphics/bdf #

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

该库可以从 bdf 字体文件中生成 embedded-graphics 能使用的:

  1. BDF Font:需要配合使用embedded-graphics/bdf/eg-bdf 库中提供的 BdfFont/BdfGlyph/BdfTextStyle 类型;
  2. MonoFont:embedded-graphics 可以直接导入使用;

先使用 otf2bdf 工具将 TTF(truetype font) 字体转换为 BDF(Bitmap Distribution Format) 类型:

Copy

brew install otf2bdf 
otf2bdf  -p 12 -r 75 -o LXGWWenKai_Regular.bdf  ~/Library/Fonts/LXGWWenKai-Regular.ttf

然后使用 eg-font-converter lib 来生成 BDF 或 MonoFont 字体:

生成 BDF 字体示例:

// /Users/zhangjun/codes/rust/bdf/eg-font-converter/src/bin/my-bdf-font.rs
zj@a:~/codes/rust/bdf/eg-font-converter$ mkdir output
zj@a:~/codes/rust/bdf/eg-font-converter$ ls
Cargo.lock  Cargo.toml  output/  src/  tests/
zj@a:~/codes/rust/bdf/eg-font-converter$ cat src/bin/my-bdf-font.rs
use eg_font_converter::{FontConverter};

// 中文 unicode 字体范围: https://en.wikipedia.org/wiki/CJK_Unified_Ideographs_(Unicode_block)
// 使用 .glyphs() 来指定要生成的字符范围 
fn main() {
    let font = FontConverter::new("/Users/zhangjun/docs/LXGWWenKai_Regular.bdf", "BDF_LXGWWenKai_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();
    font.save("output/").unwrap();  // 结果写入 output 目录下, 存入 new(bdf_file, name) 的 小写 name.rs 文件中.
}

// 运行该程序
zj@a:~/codes/rust/bdf/eg-font-converter$ cargo run --bin my-bdf-font
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.32s
     Running `/Users/zhangjun/codes/rust/bdf/target/debug/my-bdf-font`

zj@a:~/codes/rust/bdf/eg-font-converter$ ls output/
bdf_lxgwwenkai_regular_font.data  bdf_lxgwwenkai_regular_font.rs
zj@a:~/codes/rust/bdf/eg-font-converter$ ls -l output/
total 4.7M
-rw-r--r-- 1 zhangjun 310K  2 17 15:34 bdf_lxgwwenkai_regular_font.data
-rw-r--r-- 1 zhangjun 4.4M  2 17 15:34 bdf_lxgwwenkai_regular_font.rs
zj@a:~/codes/rust/bdf/eg-font-converter$ head -20 output/bdf_lxgwwenkai_regular_font.rs
const BDF_LXGWWenKai_Regular_FONT: ::eg_bdf::BdfFont = {
    const fn rect(
        x: i32,
        y: i32,
        width: u32,
        height: u32,
    ) -> ::embedded_graphics::primitives::Rectangle {
        ::embedded_graphics::primitives::Rectangle::new(
            ::embedded_graphics::geometry::Point::new(x, y),
            ::embedded_graphics::geometry::Size::new(width, height),
        )
    }
    ::eg_bdf::BdfFont {
        data: include_bytes!("bdf_lxgwwenkai_regular_font.data"),
        replacement_character: 63usize,
        ascent: 12u32,
        descent: 3u32,
        glyphs: &[
            BdfGlyph {
                character: '\0',
zj@a:~/codes/rust/bdf/eg-font-converter$

使用:

zj@a:~/codes/rust/bdf/eg-font-converter$ cp output/bdf_lxgwwenkai_regular_font.* ~/codes/esp32/st7735-lcd-examples/esp32c3-examples/src/
 
# 添加本地依赖
gzj@a:~/codes/esp32/st7735-lcd-examples/esp32c3-examples$ grep eg Cargo.toml
eg-bdf = { path = "../../../rust/bdf/eg-bdf/" } // clone https://github.com/embedded-graphics/bdf 的本地目录

代码举例:

use eg_bdf::{BdfGlyph, BdfTextStyle};
 
include!("./bdf_lxgwwenkai_regular_font.rs");

fn main() {
    let text = "Happy\u{AD}Loong\u{AD}Year!\
      Happy Hacking!\
      Happy Loong Year!\u{A0}新年快乐!\u{A0}-from Rust ESP32";
    let bdf_style = BdfTextStyle::new(&BDF_LXGWWenKai_Regular_FONT, Rgb565::WHITE);
    let textbox_style = TextBoxStyleBuilder::new()
      .line_height(LineHeight::Pixels(12)) // 字体高度与生成 otf2bdf  -p 12 一致
      .alignment(HorizontalAlignment::Justified)
      .paragraph_spacing(0)
      .build();
    let mut bounds = Rectangle::new(Point::new(0, 0), Size::new(128, 160));
    let mut text_box = TextBox::with_textbox_style(text, bounds, bdf_style, textbox_style);
    let next = text_box.draw(&mut display).unwrap();
}