使用freetype显示单个文字

1、矢量字体引入

使用点阵字库显示英文字母、汉字时,大小固定,如果放大缩小则会模糊甚至有锯齿出现,为了解决这个问题,引用矢量字体。
矢量字体形成分三步:
第1步 确定关键点,
第2步 使用数学曲线(贝塞尔曲线)连接头键点,
第3步 填充闭合区线内部空间。

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

             

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

              

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

                    

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

2、 Freetype 介绍

Freetype 是开源的字体引擎库,它提供统一的接口来访问多种字体格式文件,从而实现矢量字体显示。我们只需要移植这个字体引擎,调用对应的API 接口,提供字体文件,就可以让freetype 库帮我们取出关键点、实现闭合曲线,填充颜色,达到显示矢量字体的目的。

给定一个字符,怎么在字体文件中找到它的关键点?首先要确定该字符的编码值:比如ASCII 码、GB2312 码、UNICODE 码。如果字体文件支持某种编码格式(charset),就可以使用这类编码值去找到该字符的关键点(glyph)。有些字体文件支持多种编码格式(charset),这在文件中被称为charmaps(注意:这个单词是复数,意味着可能支持多种charset)。以simsun.ttc 为例,该字体文件的格如下:头部含有charmaps,可以使用某种编码值去charmaps 中找到它对应的关键点。下图中的“A、B、中、国、韦”等只是glyph 的示意图,表示关键点。

                                              

 

 

Charmaps 表示字符映射表,字体文件可能支持哪一些编码,GB2312、UNICODE、BIG5 或其他。如果字体文件支持该编码,使用编码值通过charmap 就可以找到对应的glyph,一般而言都支持UNICODE 码。
有了以上基础,一个文字的显示过程可以概括如下:
⚫ 给定一个字符可以确定它的编码值(ASCII、UNICODE、GB2312);
⚫ 设置字体大小;
⚫ 根据编码值,从文件头部中通过charmap 找到对应的关键点(glyph),它会根据字体大小调整关键点;
⚫ 把关键点转换为位图点阵;
⚫ 在LCD 上显示出来

如何使用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
⑨ 最后显示出来。
上面的⑤⑥⑦可以使用一个函数代替:FT_Load_Char(face, charcode, FT_LOAD_RENDER),它就可以得到位图。

3、在LCD上显示一个矢量字体

a  使用wchar_t获得字符的UNICODE值
要显示一个字符,首先要确定它的编码值。常用的是UNICODE编码,在程序里使用这样的语句定义字符串时,str中保存的要么是GB2312编码值,要么是UTF-8格式的编码值,即使编译时使用“-fexec-charset=UTF-8”,str中保存的也不是直接能使用的UNICODE值: char *str = “中”;
如果想在代码中能直接使用UNICODE值,需要使用wchar_t,宽字符,示例代码如下:

#include <stdio.h>

#include <string.h> 

#include <wchar.h>

int main( int argc, char** argv)

  wchar_t *chinese_str = L"中gif";

  unsigned int *p = (wchar_t *)chinese_str;

  int i; 

  printf("sizeof(wchar_t) = %d, str's Uniocde: \n", (int)sizeof(wchar_t));

  for (i = 0; i < wcslen(chinese_str); i++)

  {

    printf("0x%x ", p[i]);

  }

  printf("\n");

  return 0;

}

UTF-8格式保存test_wchar.c,编译、测试命令如下: book@100ask:~/10_freetype/01_wchar$ gcc -o test_wchar test_wchar.c

book@100ask:~/10_freetype/01_wchar$ ./test_wchar sizeof(wchar_t) = 4, str's Uniocde: 0x4e2d 0x67 0x69 0x66
每个wchar_t占据4字节,可执行程序里wchar_t中保存的就是字符的UNICODE值。
注意:如果test_wchar.c是以ANSI(GB2312)格式保存,那么需要使用以下命令来编译: gcc -finput-charset=GB2312 -fexec-charset=UTF-8 -o test_wchar test_wchar.c

b 使用freetype得到位图
参考 freetype-doc-2.10.2\freetype-2.10.2\docs\tutorial\image.c
使用freetype显示一个字符并不难。
使用GIT下载所有源码后,本节源码位于如下目录: 01_all_series_quickstart\ 04_嵌入式Linux应用开发基础知识\ source\10_freetype\02_freetype_show_font\freetype_show_font.c
要使用freetype得到一个字符的位图,只需要4个步骤,代码先贴出来再分析:

 

 ① 初始化freetype库 error = FT_Init_FreeType( &library ); /* initialize library */
② 加载字体文件,保存在&face中:

error = FT_New_Face( library, argv[1], 0, &face ); /* create face object */ 

/* error handling omitted */ 

slot = face->glyph;
第163行是从face中获得FT_GlyphSlot,后面的代码中文字的位图就是保存
在FT_GlyphSlot里。
③ 设置字体大小  FT_Set_Pixel_Sizes(face, font_size, 0);
④ 根据编码值得到位图
使用FT_Load_Char函数,就可以实现这3个功能:
⚫ 根据编码值获得glyph_index:FT_Get_Char_Index
⚫ 根据glyph_idex取出glyph:FT_Load_Glyph
⚫ 渲染出位图:FT_Render_Glyph
代码如下:

/* load glyph image into the slot (erase previous one) */

error = FT_Load_Char( face, chinese_str[0], FT_LOAD_RENDER );
执行FT_Load_Char之后,字符的位图被存在slot->bitmap里,即face->glyph->bitmap。

c 在屏幕上显示位图
位图里的数据格式是怎样的?参考example1.c的代码,可以得到图 6.22:

 

 

要在屏幕上显示出这些位图,并不复杂: 

 

draw_bitmap( &slot->bitmap, 

 

        var.xres/2,

 

        var.yres/2);
draw_bitmap函数代码如下,由于位图中每一个像素用一个字节来表示,在0x00RRGGBB的颜色格式中它只能表示蓝色,所以在LCD上显示出来的文字是蓝色的:

 

 

                           LCD 显示位图函数

 

 

d 编译

编译命令(如果你使用的交叉编译链前缀不是arm-buildroot-linux-gnueabihf,请自行修改命令): arm-buildroot-linux-gnueabihf-gcc -o freetype_show_font freetype_show_font.c -lfreetype
它会提示如下错误: freetype_show_font.c:12:10: fatal error: ft2build.h: No such file or directory #include <ft2build.h> ^~~~~~~~~~~~ compilation terminated.
我们不是已经编译过freetype并且把头文件复制进工具链里了吗?怎么还有这个错误?
我们编译出freetype后,得到的ft2build.h是位于freetype2目录里,我们把整个freetype2目录复制进了工具链里。
但是包括头文件时,用的是“#include <ft2build.h>”,要么改成: #include <freetype2/ft2build.h>
要么把工具链里incldue/freetype2/*.h 复制到上一级目录,我们使用这种方法:跟freetype文档保持一致。执行以下命令: book@100ask$ cd /home/book/100ask_stm32mp157_pro-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/arm-buildroot-linux-gnueabihf/sysroot/usr/include book@100ask$ mv freetype2/* ./
然后再次执行以下命令: arm-buildroot-linux-gnueabihf-gcc -o freetype_show_font freetype_show_font.c -lfreetype

 

 e 上机
将编译好的freetype_show_font文件与simsun.ttc字体文件拷贝至开发板,这2个文件放在同一个目录下,然后执行以下命令。 [root@100ask:~]# ./freetype_show_font ./simsun.ttc
或 [root@100ask:~]# ./freetype_show_font ./simsun.ttc 300
如果实验成功,我们将在屏幕中间看到一个蓝色的“繁”字。

4 在LCD上令矢量字体旋转某个角度
使用GIT下载所有源码后,本节源码位于如下目录: 01_all_series_quickstart\ 04_嵌入式Linux应用开发基础知识\ source\10_freetype\03_freetype_show_font_angle\freetype_show_font_angle.c
在实现显示一个矢量字体后,我们可以添加让该字旋转某个角度的功能,主要代码还是参照example1.c。

 a 关键代码
① 定义2个变量:角度、矩阵,如图 6.24:

 

 ② 设置角度值:

 

 ③ 设置矩阵、变形、加载位图:

 

 b 编译
编译命令(如果你使用的交叉编译链前缀不是arm-buildroot-linux-gnueabihf,请自行修改命令):

arm-buildroot-linux-gnueabihf-gcc -o freetype_show_font_angle freetype_show_font_angle.c -lfreetype -lm
 c 上机
将编译好的freetype_show_font_angle文件与simsun.ttc字体文件拷贝至开发板,这2个文件放在同一个目录下,然后执行以下命令。

[root@100ask:~]# ./freetype_show_font_angle ./simsun.ttc 90 200
如果实验成功,我们将在屏幕中间看到一个蓝色的、旋转了90度的“繁”字。

 

 

posted @ 2023-02-18 10:57  StillHolmes  阅读(441)  评论(0编辑  收藏  举报