Linux 应用层开发入门(十七)| 矢量单位显示原理与freetype显示单个汉字

在嵌入式Linux图形显示系统中,字符显示是人机交互的重要组成部分。传统的点阵字库由于字体大小固定,在缩放或旋转时容易产生模糊、锯齿等问题,难以满足高分辨率LCD和灵活显示需求。为了解决上述问题,系统通常采用矢量字体(Vector Font)结合字体引擎库进行字符渲染,其中FreeType是最常用、最成熟的开源解决方案之一。
1 矢量字体的基本原理
与点阵字体直接存储像素不同,矢量字体并不保存具体的像素信息,而是通过数学方式描述字符轮廓。一个字符的生成过程通常包括以下三个步骤:
1.1 确定关键点(Key Points)
关键点是字符轮廓中具有代表性的拐点或控制点,用于描述字符的整体结构。例如,对于字母 “A”,其笔画的端点、转折点均属于关键点。
1.2 使用数学曲线连接关键点
通过贝塞尔曲线(Bezier Curve)等数学曲线,将关键点平滑连接,形成若干条封闭或半封闭的轮廓曲线。
1.3 填充封闭区域内部空间,形成字符形状
对闭合曲线包围的区域进行颜色填充,即可得到完整的字符图形。
由于字符仅由关键点和曲线参数描述,当字体进行放大、缩小或旋转时,只需对关键点坐标进行线性或仿射变换,字符形状仍能保持平滑、不失真。这也是矢量字体能够实现无级缩放与高质量显示的根本原因。
关键特点总结:
- 字体不依赖固定分辨率
- 支持任意缩放、旋转、变形
- 显示质量由数学曲线精度决定
2 FreeType字体引擎与字体文件结构
FreeType是一个跨平台的开源字体引擎库,支持TrueType(TTF)、TrueType Collection(TTC)等多种字体格式。其核心作用是:解析字体文件→提取字符轮廓→渲染为位图供显示设备使用。
2.1 字体文件与glyph的概念
在矢量字体文件中,每一个字符对应一个glyph(字形)。glyph内部保存了该字符的关键点、曲线信息以及轮廓结构。
以 Windows 系统字体为例:
- 字体文件通常位于
C:\Windows\Fonts .ttf、.ttc文件均为矢量字体- 本实验使用的新宋体
simsun.ttc属于TTC字体集合文件
2.2 charmap(字符映射表)
字体文件并不直接通过字符“外观”查找glyph,而是通过编码值映射实现:
- 字体内部包含一个或多个Charmaps
- 每个charmap对应一种字符编码(如UNICODE、GB2312、BIG5等)
- 只要字体支持某种编码,就可以用该编码值查找到对应glyph
一般情况下:
- 现代字体几乎都支持UNICODE
- FreeType默认推荐使用UNICODE编码
2.3 字符到位图的整体流程
一个字符从“编码”到“显示”的完整流程可以概括为:
- 确定字符的编码值(ASCII/UNICODE/GB2312)
- 设置字体大小(像素或点阵尺寸)
- 通过charmap查找字符对应的glyph
- 根据字体大小调整glyph关键点
- 将glyph渲染为灰度位图
- 将位图绘制到LCD帧缓冲中
2.4 freetype的官方文档与如何使用freetype库
从https://www.freetype.org/可以下载到 “ freetype-doc 2.10.2.tar.xz”,下图中的文件就是官方文档:

参考上图中的step1、step2、step3里的内容,可以学习如何使用freetype库,总结出以下步骤:
- 初始化:FT_InitFreetype
- 加载(打开)字体Face:FT_New_Face
- 设置字体大小:FT_Set_Char_Sizes或FT_Set_Pixel_Sizes
- 选择charmap:FT_Select_Charmap
- 根据编码值charcode找到glyph_index:glyph_index=FT_Get_Char_Index(face,charcode)
- 根据glyph_index取出glyph:FT_Load_Glyph(face,glyph_index)
- 转为位图:FT_Render_Glyph
- 移动或旋转:FT_Set_Transform
- 最后显示出来
上面的5,6,7可以直接使用一个函数替代:FT_Load_Char(face, charcode, FT_LOAD_RENDER),它就可以得到位图。
int main(int argc, char **argv)
{
wchar_t *chinese_str = L"程";
FT_Library library;
FT_Face face;
int error;
FT_Vector pen;
FT_GlyphSlot slot;
int font_size = 24;
if (argc < 2)
{
printf("Usage : %s <font_file> [font_size]\n", argv[0]);
return -1;
}
if (argc == 3)
font_size = strtoul(argv[2], NULL, 0);
fd_fb = open("/dev/fb0", O_RDWR);
if (fd_fb < 0)
{
printf("can't open /dev/fb0\n");
return -1;
}
if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
{
printf("can't get var\n");
return -1;
}
line_width = var.xres * var.bits_per_pixel / 8;
pixel_width = var.bits_per_pixel / 8;
screen_size = var.xres * var.yres * var.bits_per_pixel / 8;
fbmem = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
if (fbmem == (unsigned char *)-1)
{
printf("can't mmap\n");
return -1;
}
/* 清屏: 全部设为黑色 */
memset(fbmem, 0, screen_size);
/* 显示矢量字体 */
error = FT_Init_FreeType( &library ); /* 1.初始化库 */
/* error handling omitted */
error = FT_New_Face( library, argv[1], 0, &face ); /* 2.加载或打开字体 */
/* error handling omitted */
slot = face->glyph;
FT_Set_Pixel_Sizes(face, font_size, 0); /* 3.设置字体大小 */
/* 确定座标:
*/
//pen.x = 0;
//pen.y = 0;
/* set transformation */
//FT_Set_Transform( face, 0, &pen);
/* load glyph image into the slot (erase previous one) */
error = FT_Load_Char( face, chinese_str[0], FT_LOAD_RENDER ); /* 得到位图 */
if (error)
{
printf("FT_Load_Char error\n");
return -1;
}
draw_bitmap( &slot->bitmap,
var.xres/2,
var.yres/2);
return 0;
}
3 使用FreeType显示单个汉字
3.1 使用wchar_t获取UNICODE编码
在Linux C程序中,普通char*字符串保存的通常是UTF-8或GB2312编码,不能直接作为UNICODE编码传给FreeType。
为此,需要使用宽字符类型 wchar_t:
wchar_t *chinese_str = L"中gif";
在ARM-Linux环境中:
sizeof(wchar_t) = 4- 每个
wchar_t直接保存UNICODE码值(如 “中”→0x4E2D)
这一步是显示中文矢量字体的前提条件。
3.2 FreeType 获取字符位图的核心步骤
FreeType的使用流程高度模块化,主要包括以下步骤:
①初始化与字体加载
FT_Init_FreeType:初始化 FreeType 库FT_New_Face:加载字体文件,生成 face 对象
②设置字体大小
FT_Set_Pixel_Sizes或FT_Set_Char_Sizes
③加载并渲染字符
FT_Load_Char(face, charcode, FT_LOAD_RENDER)- 查找glyph
- 加载glyph
- 渲染为位图(bitmap)
渲染完成后,字符位图存放在:
face->glyph->bitmap
3.3 位图数据与LCD显示
FreeType生成的bitmap是灰度位图:
- 每个像素占1字节
- 取值范围:0–255
- 表示像素强度(透明度)
在LCD帧缓冲中显示时:
- 可将灰度值映射到RGB颜色通道
- 示例中直接映射到蓝色通道,因此显示为蓝色字符
4 矢量字体的旋转显示原理
由于矢量字体基于数学模型描述,FreeType天然支持字符的旋转、缩放和平移。
4.1 旋转的实现机制
FreeType使用二维仿射变换矩阵对glyph进行变形:
- 定义旋转角度(弧度制)
- 构造旋转矩阵
FT_Matrix - 通过
FT_Set_Transform设置变换关系 - 再加载并渲染glyph
旋转操作发生在:
- glyph→bitmap之前
- 不影响字体质量
4.2 关键代码
①定义了两个变量,分别为矩阵与角度,如下图所示:

②设置了角度值:
angle = ( 1.0* strtoul(argv[2], NULL, 0) / 360 ) * 3.14159 * 2;

代码解析:将命令行传入的第二个参数(角度值,字符串格式)转为无符号整数,再把角度制数值换算为三角函数通用的弧度制数值,最终赋值给angle。
关键运算逻辑:先用strtoul将argv[2]的字符串角度值转为无符号长整型(base=0自动识别10/8/16进制);加1.0*强制浮点运算,避免整数除法精度丢失,再通过角度/360×2×π(π≈3.14159)完成角度到弧度的转换。
③设置矩阵、变形、加载位图:

4.3 编译与运行效果
在程序中指定:
- 字体文件
- 旋转角度(如 90°)
- 字体大小
即可在 LCD 上显示一个旋转后的汉字矢量字体,显示效果清晰、无锯齿。
5 本节总结
- 矢量字体通过关键点 + 曲线 + 填充描述字符形状
- FreeType是嵌入式Linux中最常用的矢量字体引擎
- 字符显示核心流程:编码→charmap→glyph→bitmap→LCD
- 中文显示推荐使用 UNICODE+wchar_t
- FreeType支持字符的缩放、旋转和平移,且不降低显示质量
更多推荐



所有评论(0)