LV18-01-LCD应用编程-06-FreeType简介

本文主要是LCD应用编程——FreeType简介的相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。

点击查看使用工具及版本
PC端开发环境 Windows Windows11
Ubuntu Ubuntu20.04.2的64位版本
VMware® Workstation 17 Pro 17.6.0 build-24238078
终端软件 MobaXterm(Professional Edition v23.0 Build 5042 (license))
Win32DiskImager Win32DiskImager v1.0
Linux开发板环境 Linux开发板 正点原子 i.MX6ULL Linux 阿尔法开发板
uboot NXP官方提供的uboot,NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03)
linux内核 linux-4.15(NXP官方提供)
点击查看本文参考资料
分类 网址 说明
官方网站 https://www.arm.com/ ARM官方网站,在这里我们可以找到Cotex-Mx以及ARMVx的一些文档
https://www.nxp.com.cn/ NXP官方网站
https://www.nxpic.org.cn/NXP 官方社区
https://u-boot.readthedocs.io/en/latest/u-boot官网
https://www.kernel.org/linux内核官网
其他网站 kernel - Linux source code (v4.15) - Bootlin linux内核源码在线查看
点击查看相关文件下载
分类 网址 说明
NXP https://github.com/nxp-imx NXP imx开发资源GitHub组织,里边会有u-boot和linux内核的仓库
https://elixir.bootlin.com/linux/latest/source 在线阅读linux kernel源码
nxp-imx/linux-imx/releases/tag/rel_imx_4.1.15_2.1.0_ga NXP linux内核仓库tags中的rel_imx_4.1.15_2.1.0_ga
nxp-imx/uboot-imx/releases/tag/rel_imx_4.1.15_2.1.0_ga NXP u-boot仓库tags中的rel_imx_4.1.15_2.1.0_ga
I.MX6ULL i.MX 6ULL Applications Processors for Industrial Products I.MX6ULL 芯片手册(datasheet,可以在线查看)
i.MX 6ULL Applications ProcessorReference Manual I.MX6ULL 参考手册(下载后才能查看,需要登录NXP官网)

一、LCD显示字符的方式?

1. 原始方式——取模

LCD 显示屏是由 width * height 个像素点构成的,显示字符,一个非常容易想到的方法便是对字符取模,然后在 LCD 屏上打点显示字符;以前学习过单片机的话,应该会接触过一些显示屏,如 oled、 或者其它一些点阵式的显示屏, 其实这些显示屏显示字符的原理都是一样的,如下所示:

image-20241014215505516

我们可以通过一些字符取模软件获取到字符的子模; 所谓字模,其实就是一个二维数组, 用于表示字符点阵中,哪些小方块应该要填充颜色、哪些小方块不填充颜色。如上图“正”字符点阵,这是一个宽度为64(64 个小方块)、高度为 86(86 个小方块)的字符点阵, 我们会使用一个二维数组来表示这个字符点阵:

1
unsigned char arr[86][8];

也就是一个 86 行 8 列的 unsigned char 类型数组, 数组存储的其实就是字符的位图数据, 字符点阵中的每一个小方块对应一个 bit 位,因为一行一共有 64 个小方块、也就对应 8 个字节(8 * 8 = 64); 将填充颜色的方块使用 1 表示、不填充颜色的方块使用 0 来表示,所以一个小方块刚好可以使用一个 bit 位来描述。

2. 有没有其他方式?

使用取模显示那种方式还是非常简单地,自己取模、自己写函数打点显示,但是取模很麻烦!实际的应用项目一般肯定不会这么干,除非我们的程序就是显示那么几个固定的字符。

操作系统中通常都会有很多的字体文件,如 Windows 系统“C:\Windows\Fonts”目录下就有很多的字体文件,如下所示:

image-20241014220500109

字体文件的格式也有很多种,如 otf、 ttf、 ttc 等,这里就不列举了,有兴趣可以自己百度一下; Linux 系统中, 字体文件通常会放在/usr/share/fonts 目录下,

image-20241014220630847

有了字体文件之后,我们就不需要再对字符进行取模了,它们已经编码进了字体文件中,我们只需要解析字体文件、访问字体文件,从字体文件中读取出字符的位图数据即可!

当然,这些复杂的解析过程并不需要我们自己去实现,有很多开源的字体引擎可以帮助我们来处理这些复杂的解析过程,如 freetype库。

3. 矢量字体

使用点阵字库显示英文字母、汉字时, 大小固定, 如果放大缩小则会模糊甚至有锯齿出现,为了解决这个问题,引用矢量字体。矢量字体形成分三步:

第1步 确定关键点(有些解释为字形,都是一个意思啦),

第2步 使用数学曲线( 贝塞尔曲线) 连接头键点,

第3步 填充闭合区线内部空间。

什么是关键点?以字母“ A”为例,它的的关键点如下图中的黄色所示。

image-20241017065032425

再用数学曲线(比如贝塞尔曲线)将关键点都连接起来, 得到一系列的封闭的曲线,如下图所示:

image-20241017065129404

最后把封闭空间填满颜色,就显示出一个 A 字母,如下图所示:

image-20241017065215990

如果需要放大或者缩小字体, 关键点的相对位置是不变的, 只要数学曲线平滑,字体就不会变形。

二、FreeType简介

1. FteeType是什么?

FreeType 一个完全免费(开源)的软件字体引擎库,设计小巧、高效、高度可定制且可移植,它提供了统一的接口来访问多种不同格式的字体文件,从而实现矢量字体显示。 。 它提供了一个简单、易于使用且统一的接口来访问字体文件的内容,从而大大简化了这些任务。它有以下优点:

(1)支持多种字体格式文件,并提供了统一的访问接口;

(2)支持单色位图、反走样位图渲染,这使字体显示质量达到 Mac 的水平;

(3)采用面向对象思想设计,用户可以灵活的根据需要裁剪。

但 FreeType 也有缺点,它太大了,即使是裁剪后的阉割版,其代码量也有将近 12 万行,在Flash非常小的开发板可能放不下,此时可以考虑用代码量较小的 stb_truetype 库

“FreeType”也称为“FreeType 2”,以区别于旧的、已弃用的“FreeType 1”库, Freetype 1库已经不再维护和支持了。 FreeType 是一个免费、开源、可移植且高质量的字体引擎,

2. 官网在哪?

官网应该是这个:The FreeType Project

image-20241014221036577

3. 参考文档

FreeType 库支持的功能很多、提供给用户的库函数也很多, 官网肯定也为我们提供了文档啦:

这个链接是一份中文参考文档,可以作为参考:freetype使用详解(中文) - 道客巴巴 (doc88.com),我在本地也下载了一份:freetype使用详解(中文).pdf

我们也可以下载每一个版本的文档:Index of /releases/freetype/ (gnu.org)

image-20241017075019925

像这些带有doc的,都是对应版本的官方文档。下载后解压,主要可以看这个目录:

image-20241017231255670

三、FreeType库移植

1. 下载源码

我们到这里下载:Index of /releases/freetype/ (gnu.org)

image-20241014224235379

正点原子出厂系统中的事2.6版本,这里选2.8版本,由于是第一次用,防止踩坑,和教程采用同一个版本。下载完毕后解压:

1
2
3
tar xf freetype-2.8.tar.gz
cd freetype-2.8
ls
image-20241014224612686

2. 编译源码

  • 创建安装目录
1
mkdir -p /home/sumu/9arm-linux-lib/freetype-2.8/freetype_out
  • 配置编译选项

FreeType 库基于模块化设计,意味着我们可以对其进行裁剪,将不需要的功能模块从配置中移除,减小库文件的体积;除此之外,

FreeType 还支持很多配置选项, 如果想要对 FreeType 做一些自定义配置或者对其进行裁剪,可以参考 FreeType 源码目录下 docs/CUSTOMIZE 文档,该文件对此有比较详细的说明,建议看一看,如果有需求的话。 docs 目录下还有其它很多的说明文档, 也都可以看一看。

这里我们简单地配置一下,打开 include/freetype/config/ftoption.h 文件:

1
vim include/freetype/config/ftoption.h

该文件定义了很多的配置宏,我们可以选择使能或禁用这些配置选项,具体配置哪些功能,根据自己的需求来就是了,每一个配置宏都有详细地解释说明。 这里我们打开以下两个配置宏:

1
2
#define FT_CONFIG_OPTION_SYSTEM_ZLIB
#define FT_CONFIG_OPTION_USE_PNG

我们找到这两个宏,默认情况下,这两个都被注释掉了,所以是没有使能的; 把这两个宏的注释去掉,使能这两个配置宏。 但是我后来发现这里其实没必要注释掉,配置完之后会自动打开的,编译选项中是有这两个宏的:

1
2
3
sumu@sumu-virtual-machine:~/9arm-linux-lib/freetype-2.8$ make
./builds/unix/libtool --mode=compile arm-linux-gnueabihf-gcc -pedantic -ansi -I/home/sumu/9arm-linux-lib/freetype-2.8/objs -I./builds/unix -I/home/sumu/9arm-linux-lib/freetype-2.8/include -I/home/sumu/9arm-linux-lib/zlib-1.2.10/zlib_out/include -I/home/sumu/9arm-linux-lib/libpng-1.6.44/libpng_out/include -c -Wall -I/home/sumu/9arm-linux-lib/zlib-1.2.10/zlib_out/include -I/home/sumu/9arm-linux-lib/libpng-1.6.44/libpng_out/include -I/home/sumu/9arm-linux-lib/zlib-1.2.10/zlib_out/include -L/home/sumu/9arm-linux-lib/zlib-1.2.10/zlib_out/lib -DFT_CONFIG_OPTION_SYSTEM_ZLIB -I/home/sumu/9arm-linux-lib/libpng-1.6.44/libpng_out/include -L/home/sumu/9arm-linux-lib/libpng-1.6.44/libpng_out/lib -DFT_CONFIG_OPTION_USE_PNG -DFT_CONFIG_CONFIG_H="<ftconfig.h>" -DFT2_BUILD_LIBRARY -DFT_CONFIG_MODULES_H="<ftmodule.h>" -o /home/sumu/9arm-linux-lib/freetype-2.8/objs/ftsystem.lo /home/sumu/9arm-linux-lib/freetype-2.8/src/base/ftsystem.c
libtool: compile: arm-linux-gnueabihf-gcc -pedantic -ansi -I/home/sumu/9arm-linux-lib/freetype-2.8/objs -I./builds/unix -I/home/sumu/9arm-linux-lib/freetype-2.8/include -I/home/sumu/9arm-linux-lib/zlib-1.2.10/zlib_out/include -I/home/sumu/9arm-linux-lib/libpng-1.6.44/libpng_out/include -c -Wall -I/home/sumu/9arm-linux-lib/zlib-1.2.10/zlib_out/include -I/home/sumu/9arm-linux-lib/libpng-1.6.44/libpng_out/include -I/home/sumu/9arm-linux-lib/zlib-1.2.10/zlib_out/include -L/home/sumu/9arm-linux-lib/zlib-1.2.10/zlib_out/lib -DFT_CONFIG_OPTION_SYSTEM_ZLIB -I/home/sumu/9arm-linux-lib/libpng-1.6.44/libpng_out/include -L/home/sumu/9arm-linux-lib/libpng-1.6.44/libpng_out/lib -DFT_CONFIG_OPTION_USE_PNG "-DFT_CONFIG_CONFIG_H=<ftconfig.h>" -DFT2_BUILD_LIBRARY "-DFT_CONFIG_MODULES_H=<ftmodule.h>" /home/sumu/9arm-linux-lib/freetype-2.8/src/base/ftsystem.c -fPIC -DPIC -o /home/sumu/9arm-linux-lib/freetype-2.8/objs/.libs/ftsystem.o

第一个配置宏表示使用系统安装的 zlib 库,因为 FreeType 支持 Gzip 压缩文件,会使用到 zlib 库, zlib之前我们移植好了;第二个配置宏表示支持 PNG bitmap 位图,因为 FreeType 可以加载 PNG 格式的彩色位图字形,需要依赖于 libpng 库,这个库前面我们也是移植好了。

配置好之后,保存、退出 ftoption.h 文件,接着执行如下命令对 FreeType 工程源码进行配置按理来说下面的配置应该就可以了:

1
./configure --prefix=/home/sumu/9arm-linux-lib/freetype-2.8/freetype_out/ --host=arm-linux-gnueabihf --with-zlib=yes --with-bzip2=no --with-png=yes --with-harfbuzz=no ZLIB_CFLAGS="-I/home/sumu/9arm-linux-lib/zlib-1.2.10/zlib_out/include -L/home/sumu/9arm-linux-lib/zlib-1.2.10/zlib_out/lib" ZLIB_LIBS=-lz LIBPNG_CFLAGS="-I/home/sumu/9arm-linux-lib/libpng-1.6.44/libpng_out/include -L/home/sumu/9arm-linux-lib/libpng-1.6.44/libpng_out/lib" LIBPNG_LIBS=-lpng

但是,这样配置的话,编译器无法生效:

image-20241015074149487

要通过export来设置CC环境变量才行:

1
2
export CC=arm-linux-gnueabihf-gcc
./configure --prefix=/home/sumu/9arm-linux-lib/freetype-2.8/freetype_out/ --host=arm-linux-gnueabihf --with-zlib=yes --with-bzip2=no --with-png=yes --with-harfbuzz=no ZLIB_CFLAGS="-I/home/sumu/9arm-linux-lib/zlib-1.2.10/zlib_out/include -L/home/sumu/9arm-linux-lib/zlib-1.2.10/zlib_out/lib" ZLIB_LIBS=-lz LIBPNG_CFLAGS="-I/home/sumu/9arm-linux-lib/libpng-1.6.44/libpng_out/include -L/home/sumu/9arm-linux-lib/libpng-1.6.44/libpng_out/lib" LIBPNG_LIBS=-lpng
image-20241015074333063

但是这个时候最后编译会报找不到zlib和png的库,不是很清楚原因是什么,就暂时先通过export命令来设置一下LDFLAGS、CFLAGS、CPPFLAGS好了。但是这里就很奇怪,正点原子官方教程用的是 arm-poky-linux-gnueabi-gcc 这个交叉编译工具链,不通过export命令设置那三个编译参数也能正常编译完成,我用arm-linux-gnueabihf-gcc就会出现找不到库的情况,没搞明白,后面搞明白了再补充。

1
2
3
4
5
6
export CC=arm-linux-gnueabihf-gcc
export LDFLAGS="-L/home/sumu/9arm-linux-lib/zlib-1.2.10/zlib_out/lib -L/home/sumu/9arm-linux-lib/libpng-1.6.44/libpng_out/lib"
export CFLAGS="-I/home/sumu/9arm-linux-lib/zlib-1.2.10/zlib_out/include -I/home/sumu/9arm-linux-lib/libpng-1.6.44/libpng_out/include"
export CPPFLAGS="-I/home/sumu/9arm-linux-lib/zlib-1.2.10/zlib_out/include -I/home/sumu/9arm-linux-lib/libpng-1.6.44/libpng_out/include"

./configure --prefix=/home/sumu/9arm-linux-lib/freetype-2.8/freetype_out/ --host=arm-linux-gnueabihf --with-zlib=yes --with-bzip2=no --with-png=yes --with-harfbuzz=no ZLIB_CFLAGS="-I/home/sumu/9arm-linux-lib/zlib-1.2.10/zlib_out/include -L/home/sumu/9arm-linux-lib/zlib-1.2.10/zlib_out/lib" ZLIB_LIBS=-lz LIBPNG_CFLAGS="-I/home/sumu/9arm-linux-lib/libpng-1.6.44/libpng_out/include -L/home/sumu/9arm-linux-lib/libpng-1.6.44/libpng_out/lib" LIBPNG_LIBS=-lpng

这个配置命令很长,简单地提一下,具体的细节大家可以执行”./configure –help”查看配置帮助信息。

–prefix 选项指定 FreeType 库的安装目录; –host 选项设置为交叉编译器名称的前缀。

–with-zlib=yes 表示使用 zlib;

–with-bzip2=no 表示不使用 bzip2 库;

–with-png=yes 表示使用 libpng 库;

–with-harfbuzz=no 表示不使用 harfbuzz 库。

ZLIB_CFLAGS 选项用于指定 zlib 的头文件路径和库文件路径,根据实际安装路径填写;

ZLIB_LIBS 选项指定链接的 zlib 库的名称;

LIBPNG_CFLAGS 选项用于指定 libpng 的头文件路径和库文件路径,根据实际安装路径填写;

LIBPNG_LIBS 选项用于指定链接的 libpng 库的名称。

配置完毕的时候这两个应该是开启的:

image-20241015074608820
  • 编译
1
make

如果配置前没有加这几句的话,并且使用的是arm-linux-gnueabihf-gcc:

1
2
3
export LDFLAGS="-L/home/sumu/9arm-linux-lib/zlib-1.2.10/zlib_out/lib -L/home/sumu/9arm-linux-lib/libpng-1.6.44/libpng_out/lib"
export CFLAGS="-I/home/sumu/9arm-linux-lib/zlib-1.2.10/zlib_out/include -I/home/sumu/9arm-linux-lib/libpng-1.6.44/libpng_out/include"
export CPPFLAGS="-I/home/sumu/9arm-linux-lib/zlib-1.2.10/zlib_out/include -I/home/sumu/9arm-linux-lib/libpng-1.6.44/libpng_out/include"

应该会报这个错误:

image-20241015074949082

要是加了上面三个配置项,还是用arm-linux-gnueabihf-gcc,就没问题了:

image-20241015075719592
  • 安装
1
make install
image-20241015075800634

安装完毕后,我们会得到下面的文件:

image-20241014230718118

首先我们把看一下交叉编译成功了没,看一下动态库文件的格式:

1
file libfreetype.so.6.14.0
image-20241014230614350

我们也顺便看一下有没有超链接,在拷贝的时候注意一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
sumu@sumu-virtual-machine:~/9arm-linux-lib/freetype-2.8/freetype_out$ tree
.
├── bin
│   └── freetype-config
├── include
│   └── freetype2
│   ├── freetype
│   │   ├── config
│   │   │   ├── ftconfig.h
│   │   │   ├── ftheader.h
│   │   │   ├── ftmodule.h
│   │   │   ├── ftoption.h
│   │   │   └── ftstdlib.h
│   │   # 此处省略一些头文件的显示
│   └── ft2build.h
├── lib
│   ├── libfreetype.a
│   ├── libfreetype.la
│   ├── libfreetype.so -> libfreetype.so.6.14.0
│   ├── libfreetype.so.6 -> libfreetype.so.6.14.0
│   ├── libfreetype.so.6.14.0
│   └── pkgconfig
│   └── freetype2.pc
└── share
├── aclocal
│   └── freetype2.m4
└── man
└── man1
└── freetype-config.1

11 directories, 61 files

会发现lib目录下有两个软链接,拷贝的时候需要注意一下。

3. 拷贝到共享目录

1
2
3
4
cp -avf ~/9arm-linux-lib/freetype-2.8/freetype_out ~/1sharedfiles/linux_develop/imx6ull-app-demo/lib/freetype-2.8
cd ~/1sharedfiles/linux_develop/imx6ull-app-demo/lib/freetype-2.8/lib
cp libfreetype.so.6.14.0 libfreetype.so
cp libfreetype.so.6.14.0 libfreetype.so.6

4. 移植到开发板

先拷贝到nfs服务器目录:

1
cp -a ~/9arm-linux-lib/freetype-2.8/freetype_out ~/4nfs/freetype-2.8

然后在串口终端,进入到 freetype 安装目录,将 lib 目录下的所有库文件拷贝到 Linux 系统/usr/lib 目录,注意在拷贝之前,先将开发板出厂系统中已经移植好的zlib库文件删除,执行下面这条命令:

1
2
3
4
5
6
7
# 先备份删除的文件
cd /usr/lib
ls -alh libfreetype.*
tar -czf libfreetype_usr_lib.bk.tar.gz libfreetype.*
mv libfreetype_usr_lib.bk.tar.gz ~/nfs_temp/

rm -rf /usr/lib/libfreetype.*

删除之后,再将编译得到的 freetype 库文件拷贝到开发板/usr/lib 目录,拷贝库文件时,需要注意符号链接的问题,不能破坏原有的符号链接。

1
cp -avf ~/nfs_temp/freetype-2.8/lib/libfreetype.* /usr/lib

拷贝完毕后检查一下软链接:

1
ls -alh /usr/lib/libfreetype*
image-20241015230033213