基于韦东山IMX6ULL开发板和配套资料中LCD屏幕学习
freetype库资料包:开源的字体引擎库 freetype 和字体文件 simsun.ttc,资料包括:
1、freetype-2.10.2.tar.xz
2、freetype-doc-2.10.2.tar.xz
3、libpng-1.6.37.tar.xz
4、zlib-1.2.11.tar.gz
5、simsun.ttc文件,freetype可以直接使用
freetype 依赖于 libpng, libpng 又依赖于 zlib,所以我们应该:先编译安装 zlib,再编译安装 libpng,最后编译安装 freetype。 但是,有些工具链里有 zlib, 那就不用编译安装 zlib。
freetype官方文档:FreeType Documentation
在使用字库点阵的方式在LCD上显示英文字母、汉字时,大小固定,如果放大缩小则会模糊甚至有锯齿出现,为了解决这个问题,引用矢量字体。
矢量字体形成分三步:
- 确定关键点
- 使用数学曲线(贝塞尔曲线)连接头键点
- 填充闭合区线内部空间
以字母“A”为例,它的的关键点如图中的黄色所示:
再用数学曲线(比如贝塞尔曲线)将关键点都连接起来,得到一系列的封闭的曲线,如图所示:
最后把封闭空间填满颜色,就显示出一个A字母,如图所示:
如果需要放大或者缩小字体,关键点的相对位置是不变的,只要数学曲线平滑,字体就不会变形。
在嵌入式设备上移植开源的字体渲染引擎freetype,调用对应的API接口,提供字体文件,就可以让freetype库帮我们取出关键点、实现闭合曲线,填充颜色,达到显示矢量字体的目的。
FreeType是一个开源的字体渲染引擎,它能够加载和渲染多种格式的字体文件,如TrueType(.ttf)、OpenType(.otf)等。FreeType提供了一组API来处理字体数据,包括字符的加载、渲染以及获取字符的各种信息(例如字形边界框、位图等)。它被广泛应用于各种需要显示文本的应用程序中,尤其是在那些需要高质量文本渲染的地方。
2.1 嵌入式设备使用FreeType的方法步骤
- 安装 FreeType 库:
- 下载FreeType源码。
- 配置并编译FreeType以适应你的目标平台。
- 将编译好的库文件和头文件部署到你的开发环境中。
- 编写代码:
- 初始化FreeType库。
- 加载字体文件。
- 设置字体大小。
- 渲染指定的字符或字符串。
- 处理渲染后的位图数据。
- 清理资源。
- 集成到图形系统:
- 根据你的嵌入式系统的图形库(如SDL,OpenGL ES,或者自定义的绘图函数),将渲染后的位图绘制到屏幕上。
2.2 嵌入式设备使用FreeType的注意事项
- 内存限制:嵌入式设备可能有严格的内存限制,因此要确保 FreeType 的配置和使用不会占用过多内存。
- 性能优化:根据嵌入式设备的性能特性,对 FreeType 的使用进行优化,比如选择合适的字体大小和渲染选项。
- 字体文件大小:考虑存储空间限制,选择合适大小的字体文件。
- 跨平台兼容性:确保 FreeType 的编译设置与你的目标硬件平台兼容。
3.1 example1.c源码
4.1 简单示例代码
在嵌入式设备上使用FreeType来加载字体并渲染字符 “A”,然后假设你有一个自定义的绘图函数来在屏幕上绘制点。
代码:
4.2 代码分析
代码分析参考官方freetype教程:
- 包含必要的头文件:
- 初始化FreeType库:
- 加载字体文件:
- 设置字体大小:
- 加载置顶字符:
- 获取位图信息:
- 绘制位图:
- 清理资源:
freetype 依赖于 libpng, libpng 又依赖于 zlib,所以我们应该:先编译安装 zlib,再编译安装 libpng,最后编译安装 freetype。 但是,有些工具链里有 zlib, 那就不用编译安装 zlib。文章开头资料包中包含需要的库。
基于IMX6ULL开发板验证,使用对于的工具链对freetype交叉编译。
5.1 确定头文件、库文件在工具链中的目录
先设置交叉编译工具链:
IMX6ULL开发板为例,它的工具链是arm-buildroot-linuxgnueabihf-gcc,可以执行以下命令:
可以确定头文件的系统目录为:
库文件的系统目录为:
5.2 交叉编译、安装libpng
先把freetype-2.10.2.tar.xz 、freetype-doc-2.10.2.tar.xz 、libpng-1.6.37.tar.xz 、zlib-1.2.11.tar.gz库的压缩文件上传到Ubuntu:
freetype依赖于libpng,所以需要先编译、安装libpng。命令如下:
5.3 交叉编译、安装freetype
命令如下:
freetype使用统一的接口来访问多种字体格式文件,从而实现矢量字体显示。关键点(glyph)存在字体文件中,Windows使用的字体文件在c:WindowsFonts目录下,扩展名为TTF的都是矢量字库,本次使用实验使用的是新宋字体simsun.ttc,可以在资料包中下载。
.ttf 和 .ttc 文件都是字体文件格式,但它们之间存在一些关键的区别:
- .ttf (TrueType Font)
- TrueType 字体是一种常见的计算机字体类型,由苹果公司和微软共同开发。
- 这种格式的字体文件通常包含一个单独的字体样式。例如,你可能会有一个文件用于常规样式,另一个文件用于粗体样式等。
- .ttf 文件可以跨平台使用,在 Windows、macOS 以及许多其他操作系统上都可以被支持。
- .ttc (TrueType Collection)
- TrueType Collection 是一种特殊的字体文件格式,它允许将多个 TrueType 字体打包到一个单一的文件中。
- 在 TTC 文件内,你可以找到多个字体变体(如常规、斜体、粗体等),这有助于减少文件大小并提高加载效率,因为相关联的字体数据会被共享。
- 使用 TTC 可以节省磁盘空间,并且在某些情况下可以加快字体加载速度,因为它减少了需要读取的文件数量。
.ttf 文件是单个字体样式的标准容器,而 .ttc 文件则是一个更高效的格式,能够在一个文件中封装多款相关的字体样式。对于用户而言,安装 .ttc 文件就像安装普通的 .ttf文件一样简单,但是背后的数据结构更为紧凑和优化。
freetype对.ttf和.ttc字体格式都支持:
以simsun.ttc为例,该字体文件的格如下:头部含有charmaps,可以使用某种编码值去charmaps中找到它对应的关键点。下图中的“A、B、中、国、韦”等只是glyph的示意图,表示关键点。
Charmaps表示字符映射表,字体文件可能支持哪一些编码,GB2312、UNICODE、BIG5或其他。如果字体文件支持该编码,使用编码值通过charmap就可以找到对应的glyph,一般而言都支持UNICODE码。
一个文字的显示过程可以概括如下(参考4.2 代码分析):
- 给定一个字符可以确定它的编码值(ASCII、UNICODE、GB2312)
- 设置字体大小
- 根据编码值,从文件头部中通过charmap找到对应的关键点(glyph),它会根据字体大小调整关键点
- 把关键点转换为位图点阵
- 在LCD上显示出来
6.1 在LCD上显示一个矢量字体
在LCD上显示一个矢量字体的源码:
6.1.1 使用wchar_t获得字符的UNICODE值
要显示一个字符,首先要确定它的编码值。常用的是UNICODE编码,在程序里使用这样的语句定义字符串时,str中保存的要么是GB2312编码值,要么是UTF-8格式的编码值,即使编译时使用“-fexec-charset=UTF-8”,str中保存的也不是直接能使用的UNICODE值:
如果想在代码中能直接使用UNICODE值,需要使用wchar_t,宽字符,示例代码如下:
UTF-8格式保存test_wchar.c,编译、测试命令如下:
每个wchar_t占据4字节,可执行程序里wchar_t中保存的就是字符的UNICODE值。
注意:注意:如果test_wchar.c是以ANSI(GB2312)格式保存,那么需要使用以下命令来编译:
6.1.2 使用freetype得到位图
使用 freetype 得到一个字符的位图,需要 4 个步骤:
- 初始化freetype库
- 加载字体文件,保存在&face中
第 163 行是从 face 中获得 FT_GlyphSlot,后面的代码中文字的位图就是保存在 FT_GlyphSlot 里。
- 设置字体大小
- 根据编码值得到位图
使用 FT_Load_Char 函数,就可以实现这 3 个功能:
- 根据编码值获得 glyph_index: FT_Get_Char_Index
- 根据 glyph_idex 取出 glyph: FT_Load_Glyph
- 渲染出位图: FT_Render_Glyph
执行 FT_Load_Char 之后,字符的位图被存在 slot->bitmap 里,即 face->glyph->bitmap。
6.1.3 在屏幕上显示位图
位图里的数据格式是怎样的?参考 3.1 example1.c 的代码,可以得到下图:
在屏幕上显示出这些位图:
draw_bitmap 函数代码如下,由于位图中每一个像素用一个字节来表示,在0x00RRGGBB 的颜色格式中它只能表示蓝色,所以在 LCD 上显示出来的文字是蓝色的:
6.1.4 交叉编译代码
IMX6ULL使用如下命令编译:
如果提示以下错误:
之前编译出 freetype 后,得到的 ft2build.h 是位于 freetype2 目录里,把整个 freetype2 目录复制进了工具链里。
但是包括头文件时,用的是“ #include <ft2build.h>”,要么改成:
要么把工具链里 incldue/freetype2/*.h 复制到上一级目录,使用这种方法:跟 freetype 文档保持一致。执行以下命令:
再次执行以下命令:
6.1.5 测试
将编译好的 freetype_show_font 文件与 simsun.ttc 字体文件拷贝至开发板,这 2 个文件放在同一个目录下,然后执行以下命令:
或者
6.2 在LCD上令矢量字体旋转某个角度
在LCD上令矢量字体旋转某个角度源码:
“在LCD上令矢量字体旋转某个角度源码“和“在LCD上显示一个矢量字体的源码”对比:
6.2.1 代码分析
6.2.2 交叉编译代码
IMX6ULL使用如下命令编译:
6.2.3 测试
将编译好的 freetype_show_font_angle文件与 simsun.ttc 字体文件拷贝至开发板,这 2 个文件放在同一个目录下,然后执行以下命令:
6.3 使用freetype显示一行文字
6.3.1 使用freetype显示一行文字的方法
在 LCD 上指定一个左上角坐标(x, y),把一行文字显示出来。下图中,文字的外框用虚线表示,外框的左上角坐标就是(x, y)。
6.3.1.1笛卡尔坐标系
在 LCD 的坐标系中,原点在屏幕的左上角。对于笛卡尔坐标系,原点在左下角。 freetype 使用笛卡尔坐标系,在显示时需要转换为 LCD 坐标系。
从下图可知, X 方向坐标值是一样的。
在 Y 方向坐标值需要换算,假设 LCD 的高度是 V。
在 LCD 坐标系中坐标是(x, y),那么它在笛卡尔坐标系中的坐标值为(x, V-y)。
反过来也是一样的,在笛卡尔坐标系中坐标是(x, y),那么它在 LCD 坐标系中坐标值为(x, V-y)。
6.3.1.2 每个字符的大小可能不同
在使用 FT_Set_Pixel_Sizes 函数设置字体大小时,这只是“期望值”。比如“百问网 www.100ask.net”,如果把“ .”显示得跟其他汉字一样大,不好看。
所以在显示一行文字时,后面文字的位置会受到前面文字的影响。
freetype 字体的尺寸(freetype Metrics),参考 4.2 代码分析中官方freetype教程中“Managing Glyphs”教程:
在显示一行文字时,这些文字会基于同一个基线来绘制位图:baseline。
在 baseline 上,每一个字符都有它的原点(origin),比如上图中 baseline左边的黑色圆点就是字母“ g”的原点。当前 origin 加上 advance 就可以得到下一个字符的 origin,比如上图中 baseline 右边的黑色圆点。在显示一行中多个文件字时,后一个文字的原点依赖于前一个文字的原点及 advance。
字符的位图是有可能越过 baseline 的,比如上图中字母“ g”在 baseline下方还有图像。
上图中红色方框内就是字母“g”所点据的位图,它的四个角落不一定与原点重合。
上图中那些xMin、xMax、yMin、yMax如何获得?可以使用FT_Glyph_Get_CBox函数获得一个字体的这些参数,将会保存在一个FT_BBox结构体中,以后想计算一行文字的外框时要用到这些信息:
6.3.1.3 在指定位置显示一行文字
要显示一行文字时,每一个字符都有自己外框: xMin、 xMax、 yMin、 yMax。把这些字符的 xMin、 yMin 中的最小值取出来,把这些字符的 xMax、 yMax 中的最大值取出来,就可以确定这行文字的外框了。
如下图,在指定位置(x, y)显示一行文字:
- 先指定第 1 个字符的原点 pen 坐标为(0, 0),计算出它的外框
- 再计算右边字符的原点,也计算出它的外框,把所有字符都处理完后就可以得到一行文字的整体外框:假设外框左上角坐标为(x’, y’)
- 想在(x, y)处显示这行文字,调整一下 pen 坐标即可。 pen 为(0, 0)时对应左上角(x’, y’);那么左上角为(x, y)时就可以算出pen 为(x-x’, y-y’)
6.3.1.4 freetype的几个重要数据结构
参考4.2代码分析中官方freetype文档
FT_Library:
对应 freetype 库,使用 freetype 之前要先调用以下代码:
FT_Face:
它对应一个矢量字体文件,在源码中使用 FT_New_Face 函数打开字体文件后,就可以得到一个 face。
为什么称之为 face?
估计是文字都是写在二维平面上的吧,正对着人脸?不用管原因了,总之认为它对应一个字体文件就可以。
代码如下:
FT_GlyphSlot:
插槽?用来保存字符的处理结果:比如转换后的 glyph、位图,如下图:
一个 face 中有很多字符,生成一个字符的点阵位图时,位图保存在哪里?保存在插槽中: face->glyph。
生成第 1 个字符位图时,它保存在 face->glyph 中;生成第 2 个字符位图时,也会保存在 face->glyph 中,会覆盖第 1 个字符的位图。
代码如下:
FT_Glyph:
字体文件中保存有字符的原始关键点信息,使用 freetype 的函数可以放大、缩小、旋转,这些新的关键点保存在插槽中(注意:位图也是保存在插槽中)。
新的关键点使用 FT_Glyph 来表示,可以使用这样的代码从 slot 中获得glyph:
FT_BBox:
FT_BBox 结构体定义如下,它表示一个字符的外框,即新 glyph 的外框:
可以使用以下代码从 glyph 中获得这些信息:
示例代码:
6.3.2 使用freetype显示一行文字源码
6.3.3 代码分析
6.3.3.1 计算一行文字的外框
一行文字中:后一个字符的原点=前一个字符的原点+advance。所以要计算一行文字的外框,需要按照排列顺序处理其中的每一个字符。代码如下:
6.3.3.2 调整原点并绘制
代码如下:
6.3.4 交叉编译代码
IMX6ULL使用如下命令编译:
6.3.5 测试
将编译好的 show_line 文件与 simsun.ttc 字体文件拷贝至开发板,这 2个文件放在同一个目录下,然后执行以下命令(其中的 3 个数字分别表示 LCD 的X 坐标、 Y 坐标、字体大小):
到此这篇pic头文件(pipe头文件)的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!基于freetyp的基础使用,可以进行更复杂的LCD操作。
版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权、违法违规、事实不符,请将相关资料发送至xkadmin@xkablog.com进行投诉反馈,一经查实,立即处理!
转载请注明出处,原文链接:https://www.xkablog.com/cjjbc/20988.html