LuatOS 字体使用说明
作者:江访 | 最后修改:2026-06-11
一、概述
本文档面向需要在 LuatOS UI相关核心库中使用文字显示的客户,涵盖以下内容:
- 字体类型:固件内置 ttf 矢量字体、固件内置灰度点阵字体、固件内置单色点阵字体、文件系统中的 ttf 文件、文件系统中的 bin 点阵字体文件
- 使用场景:airui 核心库、lcd 核心库、eink 核心库、u8g2 核心库
- 字体制作:ttf 精简提取、bin 点阵字体生成
注意事项
- 固件内置 ttf 数据:大部分支持 airui 的模块固件内置了 MiSans-Demibold 字体的 ttf 数据,涵盖 GB2312 一级和二级汉字,直接在 airui 或 hzfont 中选用即可。
- 固件内置灰度点阵数据:部分没有内置 ttf 的固件(如 Air8000 15/115 16/116号固件)内置了16号灰度单色点阵数据,供 airui 直接使用。
- 12 号单色点阵中文字体:lcd、eink、u8g2 核心库的固件内仅内置了 12 号单色点阵中文字体,更大字号的中文点阵字体均未内置。如需大号中文显示,建议使用 hzfont 矢量字体。
- bin 点阵字体文件:仅 lcd 核心库支持通过
lcd.setFontFile()加载使用。 - ttf 字体文件:可烧录到文件系统或外置存储,各核心库加载方式不同。
- hzfont 矢量字体初始化差异:
- airui — 使用
airui.font_load({type="hzfont", ...}),不需要调用hzfont.init() - lcd — 需要先调用
hzfont.init(),再调用lcd.drawHzfontUtf8() - eink — 直接调用
eink.drawHzfont(),不需要先执行hzfont.init();仅支持固件内置 ttf - u8g2 — 调用
u8g2.SetHzFont()配置,之后使用u8g2.DrawUTF8()渲染,不需要先执行hzfont.init()
二、LuatOS UI功能的核心库和字体关系
2.1 字体关系图
2.2 名称解释
| 类型 | 名称 | 说明 |
| 核心库 | airui核心库 | airui 是基于 LVGL 9.4 版本进行图形层封装的 LuatOS 核心库,把常用组件、事件管理、输入和基础视觉主题封装为更易上手的 Lua 接口,便于在支持 LuatOS 的设备和 PC 上统一开发。 |
| lcd核心库 | LCD 核心库是一个功能丰富的显示屏控制接口,支持多种接口类型的 LCD 屏幕,包括 SPI、QSPI、RGB 等。该模块提供了显示屏初始化、图形绘制、文本显示、图像处理、屏幕休眠、唤醒等功能。 LCD 核心库适合简单图形显示和绘制,不适合较复杂UI的设计和开发。 | |
| u8g2核心库 | u8g2 图形处理库是 LuatOS 的显示屏驱动库,支持多种 OLED 和 LCD 单色屏幕,提供丰富的图形绘制功能。 | |
| eink核心库 | eink墨水屏操作库是LuatOS的电子墨水屏驱动库,支持微雪电子多种尺寸和型号的黑白电子墨水屏。 | |
| 字体分类 | 灰度点阵字库 | 固件内固定字号大小灰度显示字体点阵数据 |
| 矢量字库 | 支持12-255号字体大小,灰度显示的字体数据,分为固件内置和自定义2种 | |
| 单色点阵字库 | 由单色点阵构成的固定大小的字体点阵数据,分为固件内置和自定义2种 | |
| 字体 | 固件内置的ttf数据 | 大部分支持airui的模块固件内置了ttf数据,使用的MiSans-Demibold字体,初始化后可灰度显示12-255号 GB2312 一级和二级汉字和英文 |
| 固件内置airui 16号灰度字体点阵数据 | 固件内无法完整放下内置的ttf数据时,选择了内置一个固定16号字体大小的灰度字体点阵数据 | |
| 文件系统中的ttf文件 | 固件内未内置,可以自定义生成并烧录到模块文件系统、外置sd/tf卡、外置nand_flash、外置nor_flash中的.ttf文件 | |
| 固件内置单色英文字体点阵数据 | 固件内置支持以点阵显示12、16、18、20、22、24、32号英文字母及英文符号的数据 | |
| 固件内置单色英文+12号中文字体点阵数据 | 固件内置支持以12、16、18、20、22、24、32号点阵显示英文字母及英文符号,加上以12号点阵显示中文的数据 | |
| 文件系统中的bin文件 | 自定义生成的单色点阵字体数据 |
2.3 各核心库字体支持速查
使用内置字体速查
| 核心库 | 固件内置 ttf 矢量字体 | 固件内置16号灰度点阵 | 固件内置单色点阵英文字体 | 固件内置 12 号单色点阵中文字体 |
|---|---|---|---|---|
| airui | √ | √ | — | — |
| lcd | √ | — | √ | √ |
| eink | — | — | √ | √ |
| u8g2 | — | — | √ | √ |
加载外部 ttf 能力速查
| 核心库 | 加载外部 ttf | 加载接口 | 使用接口 |
|---|---|---|---|
| airui | √ | airui.font_load({type="hzfont", path="/xxx.ttf"}) |
组件自动使用 |
| lcd | √ | hzfont.init("/xxx.ttf") |
lcd.drawHzfontUtf8() |
| eink | —(仅支持内置 ttf) | — | eink.drawHzfont() |
| u8g2 | √ | u8g2.SetHzFont("/xxx.ttf") |
u8g2.DrawUTF8() |
三、LuatOS 固件与字体的关系
3.1 airui 固件与字体关系
| 支持 airui 的固件 | 内置 ttf 数据 | 内置灰度点阵 | 文件系统 ttf | 推荐使用方式 |
|---|---|---|---|---|
| 大部分支持 airui 的固件 | √ | — | 可选 | 见 5.1.1 使用固件内置 ttf 数据 |
| Air8000 15/115、16/116 号固件 | — | √ | 可选 | 见 5.1.2 仅使用固件内置灰度点阵数据(纯灰度点阵) 或 5.1.3 使用内置灰度点阵 + 文件系统 ttf 文件(叠加外置 ttf) |
| Air8101 | — | — | 必选 | 见 5.1.4 仅使用文件系统中的 ttf 文件 |
3.2 lcd 固件与字体关系
| 支持 lcd 的固件 | 内置单色点阵英文字体 | 内置 12 号单色点阵中文字体 | hzfont 支持 | bin 字体支持 |
|---|---|---|---|---|
| Air780EHM/EGH/EHV/Air8000 等 | √ | √ | √(14/114 号固件,见 5.2.3 使用 hzfont 矢量字体) | √(见 5.2.2 使用 bin 字体文件) |
| Air780EPM | √ | — | — | √(见 5.2.2 使用 bin 字体文件) |
| Air8101 | √ | — | √(102/104 号固件,见 5.2.3 使用 hzfont 矢量字体) | √(见 5.2.2 使用 bin 字体文件) |
注意:hzfont 支持需对应固件版本,bin 字体文件仅 lcd 核心库支持。
3.3 eink 固件与字体关系
| 支持 eink 的固件 | 内置单色点阵英文字体 | 内置 12 号单色点阵中文字体 | hzfont 支持 |
|---|---|---|---|
| Air780EHM/EHV/EGH/Air8000 等 | √ | √ | √(仅内置 ttf,见 5.4.2 使用 hzfont 矢量字体) |
注意:eink 的 hzfont 仅支持固件内置 ttf 数据,不支持加载外部 ttf 文件。
3.4 u8g2 固件与字体关系
| 支持 u8g2 的固件 | 内置单色点阵英文字体 | 内置 12 号单色点阵中文字体 | hzfont 支持 |
|---|---|---|---|
| Air780EHM/EHV/EGH/Air8000/Air8101 等 | √ | √ | √(支持内置/外置 ttf,见 5.3.2 使用 hzfont 矢量字体) |
注意:u8g2 的 hzfont 支持通过 path 参数加载外部 ttf 文件。
四、非固件内置字体的制作
4.1 ttf 字体文件的制作
4.1.1 选择 ttf 字体类型
选择你获得授权使用的 ttf 格式文件,比如:宋体、黑体,假设选择的是小米字体。
4.1.2 从字体中提取所需字符
使用 LuatOS_Font_Tools.exe 工具从字体中提取所需字符,生成精简后的 ttf 文件。
- 导入你的.ttf文件

- 选择需要的字符集 可快捷选择字符集、手动选择字符集、输入自定义内容,比如:勾选一二级中文+英语+法语


- 将选择的字符集从当前.ttf文件中提取出来生成精简后的 ttf 文件。

4.2 bin 字体文件的制作和烧录
bin 点阵字体文件使用 u8g2_font_tool 工具生成,仅 lcd 核心库支持通过 lcd.setFontFile() 加载使用。
4.2.1 注意事项
- 字体和软件需要放到非中文目录下
- 一定要能显示完整的字体名才能进行转换
- 字体命名长度不能超过 23 个字符,例如
dinglie_16_chinese.bin
4.2.2 选择字体类型
选择你获得授权使用的 ttf 或 otf 格式的字体文件,假设选择的是小米字体。
4.2.3 从字体中提取所需字符
-
导入你的 .ttf 文件并选择映射表
- 选择字体
- 选择映射表:自定义(手动输入所需字符)或 常用中文/全部中文(完整字库)
- 设置字体大小和间距
- 点击字体转换,生成 .bin 文件
4.3 字体文件的烧录
ttf 和 bin 字体文件的烧录方式一致,均支持以下四种方式。
4.3.1 烧录方式一:烧录到模块文件系统
将字体文件单独放入一个空文件夹中,烧录固件时选择对应的文件夹,然后选择下载底层和脚本进行烧录。

使用方式: 见 5.1 airui 核心库、5.2 lcd 核心库、5.3 u8g2 核心库
4.3.2 烧录方式二:烧录到模块脚本空间
将字体文件加载到脚本和资源列表,随代码一起烧录。

使用方式: 见 5.1 airui 核心库、5.2 lcd 核心库、5.3 u8g2 核心库
4.3.3 烧录方式三:使用 sd/tf 卡中的字体文件
- 将生成的字体文件复制到 sd/tf 卡的根目录。
- 参考 FAT32 文件系统挂载 sd/tf 卡。
- 将
/sd/MyFont.ttf作为对应接口的path参数即可使用。
-- 初始化 SPI1 和 TF 卡
local spi_id, pin_cs = 0, 8
gpio.setup(pin_cs, 1)
spi_sd_device = spi.deviceSetup(spi_id, pin_cs, 0, 0, 8, 24000000)
-- 挂载 TF 卡
local max_retries = 3
local retry_count = 0
local mount_success = false
while retry_count < max_retries and not mount_success do
result, err = fatfs.mount(fatfs.SPI, "/sd", spi_sd_device)
if result then
mount_success = true
log.info("SD", "挂载成功")
else
retry_count = retry_count + 1
sys.wait(500)
end
end
使用方式: 见 5.1 airui 核心库、5.2 lcd 核心库、5.3 u8g2 核心库
4.3.4 烧录方式四:使用外置 nand_flash、nor_flash 中的字体文件
- 参考 SPI Flash 通用驱动挂载 flash。
local spi_id, pin_cs, speed = 0, 8, 24000000
little_flash_spi_device = spi.deviceSetup(spi_id, pin_cs, 0, 0, 8, speed)
if little_flash_spi_device then
little_flash_device = lf.init(little_flash_spi_device)
if little_flash_device then
local ok = lf.mount(little_flash_device, "/little_flash")
if not ok then
ok = lf.mount(little_flash_device, "/little_flash")
end
end
end
- 通过 HTTP 下载字体到 flash,或从模块文件系统复制到外挂 flash。
-- 方式一:通过 HTTP 下载字体文件到外挂 flash
http.request("GET", "https://example.com/path/MyFont.ttf", nil, nil,
{ dst = "/little_flash/MyFont.ttf" },
function(result, status, header, body)
if result then
log.info("flash", "字体下载成功")
end
end
)
-- 方式二:从模块文件系统复制字体到外挂 flash
local ttf_data = io.readFile("/MyFont.ttf")
if ttf_data then
io.writeFile("/little_flash/MyFont.ttf", ttf_data)
end
- 使用方式: 见 5.1 airui 核心库、5.2 lcd 核心库、5.3 u8g2 核心库
五、字体文件的使用
5.1 airui 核心库
5.1.1 使用固件内置 ttf 数据
airui.font_load({
type = "hzfont",
path = nil, -- nil 表示使用固件内置的 TTF 数据
size = 20,
cache_size = 1048,
antialias = 1,
})
airui.label({
text = "中文显示测试",
x = 10, y = 50, w = 100, h = 200,
})
5.1.2 仅使用固件内置灰度点阵数据
使用固件内置的灰度字体点阵数据时,不需要调用
airui.font_load()接口。
airui.label({
text = "中文显示测试",
x = 10, y = 50, w = 100, h = 200,
})
5.1.3 使用内置灰度点阵 + 文件系统 ttf 文件
-- 使用内置灰度点阵(无需 font_load,组件直接使用)
airui.label({
text = "中文显示测试",
x = 10, y = 50, w = 100, h = 200,
})
-- 叠加加载外部 ttf 文件,支持更大字号和抗锯齿
airui.font_load({
type = "hzfont",
path = "/luadb/MyFont.ttf", -- ttf 文件随代码一起烧录时
size = 16,
cache_size = 256,
antialias = 1,
global = false
})
airui.label({ text = "你好LuatOS123", x = 10, y = 100, w = 300, h = 200, font_size = 36, font = "hzfont"})
5.1.4 仅使用文件系统中的 ttf 文件
airui.font_load({
type = "hzfont",
path = "/MyFont.ttf", -- ttf 文件烧录到内置文件系统时
size = 16,
cache_size = 256,
antialias = 1,
load_to_psram = true,
})
airui.label({ text = "你好LuatOS123", x = 10, y = 100, w = 300, h = 200, font_size = 36, font = "hzfont"})
5.2 lcd 核心库
5.2.1 使用固件内置单色点阵字体
支持的字体常量:
- 英文字体:
lcd.font_opposansm12/lcd.font_opposansm16/lcd.font_opposansm18/lcd.font_opposansm20/lcd.font_opposansm22/lcd.font_opposansm24/lcd.font_opposansm32 - 12号中文字体:
lcd.font_opposansm12_chinese(固件内仅内置此号) - 天气图标字体:
lcd.font_open_iconic_weather_6x_t - 符号字体:
lcd.font_unifont_t_symbols
lcd.init("st7796", { port = lcd.HWID_0, pin_pwr = 7, pin_rst = 19, direction = 0, w = 320, h = 480 })
lcd.setColor(0xFFFF, 0x0000)
-- 英文字体
lcd.setFont(lcd.font_opposansm12); lcd.drawStr(20, 30, "Hello 12")
lcd.setFont(lcd.font_opposansm24); lcd.drawStr(20, 60, "Hello 24")
-- 12号中文字体
lcd.setFont(lcd.font_opposansm12_chinese); lcd.drawStr(20, 130, "12号中文显示测试")
lcd.flush()
5.2.2 使用 bin 字体文件
lcd.init("st7796", { port = lcd.HWID_0, pin_pwr = 7, pin_rst = 19, direction = 0, w = 320, h = 480 })
-- 烧录到脚本分区时用 /luadb/,烧录到文件系统时用 /
local result = lcd.setFontFile("/luadb/dinglie_16_chinese.bin")
lcd.setColor(0xFFFF, 0x0000)
lcd.setFont(lcd.font_opposansm12_chinese)
lcd.drawStr(20, 30, "自定义点阵字体显示测试")
lcd.flush()
5.2.3 使用 hzfont 矢量字体
lcd 核心库需要先调用
hzfont.init(),再使用lcd.drawHzfontUtf8()。
lcd.init("st7796", { port = lcd.HWID_0, pin_pwr = 7, pin_rst = 19, direction = 0, w = 320, h = 480 })
lcd.setupBuff(nil, true)
lcd.autoFlush(false)
-- 初始化 hzfont(无参数使用固件内置字库)
hzfont.init()
-- 或加载外部 ttf:hzfont.init("/luadb/MyFont.ttf")
lcd.setColor(0x0000, 0xFFFF)
lcd.drawHzfontUtf8(10, 30, "合宙LuatOS 20号", 20, 0xF800, 1)
lcd.drawHzfontUtf8(10, 80, "合宙LuatOS 40号", 40, 0x07E0, 1)
lcd.flush()
5.3 u8g2 核心库
5.3.1 使用固件内置单色点阵字体
支持的字体常量:
- 英文字体:
u8g2.font_opposansm10/u8g2.font_opposansm12/u8g2.font_opposansm16/u8g2.font_opposansm18/u8g2.font_opposansm20/u8g2.font_opposansm22/u8g2.font_opposansm24/u8g2.font_opposansm32 - 中文字体:
u8g2.font_opposansm12_chinese(固件内仅内置此号)
local result = u8g2.begin({
ic = "ssd1306", direction = 0, mode = "spi_hw_4pin",
spi_id = 0, spi_res = 20, spi_dc = 21, spi_cs = 24,
}, { width = 128, height = 64 })
u8g2.SetFontMode(1)
-- 英文字体
u8g2.SetFont(u8g2.font_opposansm12); u8g2.DrawUTF8("Hello 12", 0, 16)
u8g2.SetFont(u8g2.font_opposansm24); u8g2.DrawUTF8("Hello 24", 0, 60)
-- 12号中文字体
u8g2.ClearBuffer()
u8g2.SetFont(u8g2.font_opposansm12_chinese); u8g2.DrawUTF8("12号中文测试", 0, 20)
u8g2.SendBuffer()
5.3.2 使用 hzfont 矢量字体
u8g2 核心库通过
u8g2.SetHzFont()加载 hzfont,不需要先调用hzfont.init()。支持通过 path 参数加载外部 ttf 文件。
local result = u8g2.begin({
ic = "ssd1306", direction = 0, mode = "spi_hw_4pin",
spi_id = 0, spi_res = 20, spi_dc = 21, spi_cs = 24,
}, { width = 128, height = 64 })
-- u8g2.SetHzFont() -- 使用固件内置字库
-- u8g2.SetHzFont("/luadb/MyFont.ttf") -- 从文件系统加载 ttf
u8g2.SetHzFont()
u8g2.DrawUTF8("合宙LuatOS 矢量字体", 0, 30)
u8g2.SendBuffer()
注意: 1. u8g2 核心库不支持加载
.bin字体文件。 2. 使用u8g2.SetHzFont()后,后续的u8g2.DrawUTF8()自动使用矢量字体渲染。 3. 如需回到内置点阵字体,可再次调用u8g2.SetFont(u8g2.font_xxx)。
5.4 eink 核心库
5.4.1 使用固件内置单色点阵字体
支持的字体常量:
- 英文字体:
eink.font_opposansm12/eink.font_opposansm16/eink.font_opposansm18/eink.font_opposansm20/eink.font_opposansm22/eink.font_opposansm24/eink.font_opposansm32 - 中文字体:
eink.font_opposansm12_chinese(固件内仅内置此号)
-- eink 初始化前必须先初始化 SPI
local spi_id, pin_cs, pin_dc, pin_busy, pin_reset = 0, 31, 30, 32, 29
spi_eink = spi.deviceSetup(spi_id, pin_cs, 0, 0, 8, 20 * 1000 * 1000, spi.MSB, 1, 1)
eink.init(eink.MODEL_1in54_V2,
{ port = "device", pin_dc = pin_dc, pin_busy = pin_busy, pin_rst = pin_reset }, spi_eink)
eink.setWin(200, 200, 0)
eink.clear(1, true)
-- 英文字体
eink.setFont(eink.font_opposansm22); eink.print(35, 34, "LuatOS-eink", 0)
eink.setFont(eink.font_opposansm12); eink.print(20, 60, "Hello 12", 0)
-- 12号中文字体
eink.setFont(eink.font_opposansm12_chinese); eink.print(20, 120, "12号中文显示测试", 0)
eink.show(0, 0, true)
5.4.2 使用 hzfont 矢量字体
eink 核心库通过
eink.drawHzfont()直接渲染 hzfont 矢量字体,不需要先调用hzfont.init()。注意该接口仅支持固件内置 ttf,不支持加载外部 ttf 文件。
-- eink 初始化前必须先初始化 SPI
local spi_id, pin_cs, pin_dc, pin_busy, pin_reset = 0, 31, 30, 32, 29
spi_eink = spi.deviceSetup(spi_id, pin_cs, 0, 0, 8, 20 * 1000 * 1000, spi.MSB, 1, 1)
eink.init(eink.MODEL_1in54_V2,
{ port = "device", pin_dc = pin_dc, pin_busy = pin_busy, pin_rst = pin_reset }, spi_eink)
eink.setWin(200, 200, 0)
eink.clear(1, true)
-- 直接使用 eink.drawHzfont(无需 hzfont.init())
eink.drawHzfont(20, 40, "合宙LuatOS 16号", 16, 1)
eink.drawHzfont(20, 80, "合宙LuatOS 24号", 24, 1)
eink.drawHzfont(20, 130, "合宙LuatOS 36号", 36, 1)
eink.show(0, 0, true)
注意: 1. eink 核心库不支持加载
.bin字体文件。 2.eink.drawHzfont()直接调用即可,不要额外执行hzfont.init()。 3.eink.drawHzfont()仅支持固件内置 ttf,不支持外部 ttf。