2、数码相框之显示文字

上一节:1、数码相框之框架分析

下一节:3、数码相框之电子书

本节源码在github仓库show_fontfreetype中。

1、字符的编码方式

1.1、串口发送数据给PC机的流程

在这里插入图片描述
比如要发送copy这个字符串,那么2440使用串口挨个发送43、6F、70,表示"C"、"O"、"P"。PC机接收到之后就会显示出"C"、"O"、"P"这些字符。

既我们要搞清楚三点:数字、数字代表什么、显示为什么。

1.2、数字代表什么

PC中字符编码的发展

在这里插入图片描述

中国人使用的编码

在这里插入图片描述
其中用什么值表示汉字就称为字符编码(charset),比如"中"字使用"D6 D0"表示,那么这一套字符编码就称为国标(GB2312)。港澳台使用的字符编码BIG5,比如"D6 D0"表示"笢"

那么从数字数字代表什么就引入了字符编码,如:ASCII码GBKBIG5。这就会有使用不同编码方式编写的文字之间不能互通,比如使用GB2312编码方式解析BIG5编写的文字就会导致错误出现。

世界统一使用unicode编码表统一字符编码

在这里插入图片描述
unicode只是建立了数值字符之间的关系,既用某一个数值表示某一个符号

这么编码表怎么来表示它呢?比如表示abc这个字符串使用3字节表示一个字符的话,在ASCII码中为 0x61、0x62、0x63,所有编码方式都兼容ASCII码。

那么使用使用3字节来表示unicode码的话,abc表示为:

0x000x000x61
0x000x000x62
0x000x000x63

既使用了9字节来表示abc,这就会造成浪费,那么就有UTF-8、UTF-16LE、UTF-16BE等等方法来表示unicode码

使用4中不同编码方式表示"abc中"

  • ANSI,会使用计算机默认的编码格式打开。
    在这里插入图片描述

  • UTF-8,使用变长字节表示,前面的EF BB BF表示它是UTF-8的编码格式。
    在这里插入图片描述
    UTF-8实现方法如下:
    在这里插入图片描述
    中字的表示方法如下:
    在这里插入图片描述

  • UTF-16BE(大端,使用FE FF表示,2字节表示),大端里高字节数据61、62、63在后面,对于纯英文字符浪费一个字节
    在这里插入图片描述

  • UTF-16LE(小端,使用FF FE表示,2字节表示),小端里高字节数据61、62、63在前面,对于纯英文字符浪费一个字节。
    在这里插入图片描述

1.3、显示为"什么"

字符显示原理

从一个数字到代表什么,使用字符编码来解决;那么从代表什么到显示"为"什么使用字体来解决。

如之前的图中,2440将数字43发送给串口,串口使用这个43到字体文件中找到对应字体的字模点阵将其显示出来;怎么从字体文件中找到那个字呢?字体文件中含有编码表字体数据,根据这两项显示出正确的字符。

编辑一段代码,编译运行之后查看其信息:

#include <stdio.h>
int main(int argc, char **argv)
{
	int i = 0;
	unsigned char *str = "abc中";
	while (str[i]) {
		printf("%02x ", str[i]);
		i++;
	}
	printf("\n");
	return 0;
}

上述代码分别以ANSIUTF-8格式保存,再进行编译运行:
在这里插入图片描述
源文件用不同的编码方式编写,会导致执行结果不一样。怎么解决?编译程序时,要指定charset(字符集)。

man gcc
/charset
-finput-charset=charset  表示源文件的编码方式, 默认以UTF-8来解析
-fexec-charset=charset   表示可执行程序里的字符以什么编码方式来表示,默认是UTF-8
gcc -o a a.c  /* 默认是UTF-8 */

现在指定源文件的编码方式为GBK,输出可执行程序的编码方式为UTF-8,进行编译;

gcc -finput-charset=GBK -fexec-charset=UTF-8 -o utf-8_2 ansi.c

测试如下,这就显示正确了。
在这里插入图片描述

字符显示流程

  • 在一个源文件中使用某个数值来表示某个字符;
  • 怎样知道某个数值表示某个字符呢?引入charset字符集(字符编码),有ANSIGBKBIG5等等;
  • 这些字符集之间不通用,引入unicode编码表,编码表指定某个数值对应某个字符;
  • 怎么表示这个unicode编码表呢?有UTF-8UTF-16BEUTF16-LE等等方法;
  • 最后文字怎样显示呢?软件收到一个数值就去查找编码表来确定是哪一个字符,这个文字以什么方式显示出来?要去字体文件中找到这个字符对应的字体数据,字体文件中肯定有编码表,就根据这个编码表来进行显示。

2、点阵显示

2.1、介绍

LCD控制器取出SDRAM显存里若干字节的数据(代表一个像素),发给LCD就能显示某个颜色了,取到最后一个格子的数据就会从头开始取数据。
在这里插入图片描述
我们想在LCD上显示一个字的话,使用16x8点阵数据,有些点亮有些不点亮。在某个位置显示某个字符,在显存中找到这个位置,根据点阵设置显存中的数据。

如果要显示字母A,点阵数据如下:
在这里插入图片描述

2.2、写测试程序

点阵源码show_font.c在github仓库

2.3、调试代码

编译程序

arm-linux-gcc -o show_font show_font.c
cp show_font /work/nfs_root/fs_mini_mdev_new
cp HZK16 /work/nfs_root/fs_mini_mdev_new

配置、修改内核支持把lcd.c编译进去

sudo cp /work/drivers_and_test_new/10th_lcd/lcd.c drivers/video/

修改Makefile

sudo vim drivers/video/Makefile

若改变代码将其放在tq2440或者mini2440上:
在这里插入图片描述
再修改Makefile为对应的平台:
mini2440:
在这里插入图片描述
三星2440:
在这里插入图片描述

配置内核

make menuconfig
Device Drivers  ---> 
	 Graphics support  ---> 
	 		<*> Support for frame buffer devices  ---> 
	 				  <*>   S3C2410 LCD framebuffer support  
make uImage
cp arch/arm/boot/uImage /work/nfs_rootuImage_lcd_2.2

使用新内核启动

nfs 32000000 192.168.2.22:/work/nfs_root/uImage_lcd_2.2; bootm 32000000
//将程序放在下面TQ2440和mini2440上同样可以通过测试
nfs 32000000 192.168.1.123:/work/nfs_root/uImage_tq2440; bootm 32000000
nfs 32000000 192.168.1.123:/work/nfs_root/uImage_mini2440; bootm 32000000

tty1也就是lcd当作控制台显示,去掉tty1:...就是显示在串口console....中:
在这里插入图片描述

测试

三星2440中:
在这里插入图片描述
TQ2440中:
在这里插入图片描述

mini2440中:
在这里插入图片描述

3、freetype

下面使用到的代码和文档在GitHub仓库中

3.1、freetype理论介绍

显示一个字符

在上一小节里面,从点阵字库里面把英文字母或汉字的字模取出来,然后在 LCD 上面显示。这种方法有一个缺点,一旦选定了点阵字库文件之后,这个文字的大小就定死了,不能够缩放。
但是在我们的日常生活中,字体是可以缩放的。这些字体称之为矢量字体。
在这里插入图片描述
矢量字体在字体文件里面存放的方式如下:

  • 1、一个字符就是存储了若干条闭合曲线的关键点
  • 2、使用数学曲线(贝塞尔曲线)链接关键点
  • 3、填充这些关键点的内部空间构成一个字符

构造字体文件

在这里插入图片描述
制作字库的时候,把字描出来,让字精细,格子必须细。在格子里面以点阵的方式描绘出想要的字。美工人员做字的样子,程序员提取关键点,及相对位置制作为字库文件。

一个字符的轮廓如上图,美工先作图画出,程序员再将提取关键点(glyph)及其相对位置。构成一个charmaps(s表示可能支持多种编码方式,ANSI、unicode等等)将所有字符存储器中,一个一个的字符成为glyph(字形)。

文字的显示过程

  • 1、给定一个汉字、字符,可以从字体文件确定它的编码值(是GBK、unicode还是等等);
  • 2、根据编码值从字体文件中找到它的字形"glyph"
  • 3、设置字体的大小
  • 4、使用某些函数把glyph里面的点缩放为第3步的字体大小;
  • 5、转换为位图点阵;
  • 6、在LCD上显示出来

编程实现文字的显示过程

文档参考
在这里插入图片描述
其中使用一个函数 FT_Load_Char( face, text[n], FT_LOAD_RENDER );代替了左边的三个函数找到、取出、转换位图

3.2、在PC上测试freetype

freeType中各个API介绍

官方文档:freetype-doc-2.4.10\freetype-2.4.10\docs\tutorial 下面提供了四个例子:
在这里插入图片描述
后面三个例子是 C++的,第一个例子是 C语言的。

对接口不了解的话,源代码里有接口参考:freetype-2.4.10\docs\reference

给定字符大小,计算一个字符用多少像素表示:

下图中`FT_Set_Char_Size`函数参数解析:

char_width : 字符宽度 单位 :1/64 point point = 1/72 inch
若 char_with 写 100,则字体物理大小为 100*(1/64)*(1/72) 英寸
hor_resolution : 水平方向分辨率 单位:dpi (dpi: dots-per-inch 每英寸里面有多少个像素)
ver_resolution : 垂直方向分辨率 单位:dpi (dpi: dots-per-inch 每英寸里面有多少个像素)

“像素”pix 实际上是投影光学上的名词,一个像素的大小尺寸不太好衡量,其实它就是屏幕上的一个光点。在计算机显示器和电
视机的屏幕上都使用到像素作为它们的基本度量单位,分辨率越高,像素就越小。

假设 char_width = 100,hor_resolution = ver_resolution = 200,表明一个英寸里面有 200 像素,则一个字符的像素为:
100*(1/64)*(1/72)*200 = 4.3(像素)

在这里插入图片描述
字符旋转:

笛卡尔坐标:左图所示 LCD 坐标: 右图所示
字体文件,字体函数用的都是笛卡尔坐标
由于在笛卡尔左边中的原点为左下的位置,而LCD左边的原点为左上的位置,所以如果要在LCD中的(x,y)坐标出显示某体字体,则转化到
笛卡尔左边中要进行左边变换,变换为x’=x,y’=height-y

在这里插入图片描述

测试freeType中的例子

显示字符
tar xjf freetype-2.4.10.tar.bz2 
cd freetype-2.4.10
./configure
make
sudo make install

gcc -o example1 example1.c  -I /usr/local/include/freetype2 -lfreetype -lm
gcc -finput-charset=GBK -fexec-charset=UTF-8 -o example1 example1.c  -I /usr/local/include/freetype2 -lfreetype -lm

-I (大i):表示指定头文件路径
-l (小l):表示指定库
-lm :表示数学库
./example1 ./simsun.ttc abc		/* example1放在有simsun文件的目录下才能运行 */

编译03.freetype\01th_pc\01th_english中的example1.c
修改宽度和高度:
在这里插入图片描述
想在新的坐标(0,40)的地方开始显示:
之前:
在这里插入图片描述
修改为:
在这里插入图片描述
再次编译运行:
A

显示汉字

代码为03.freetype\01th_pc\02th_chinese中的example1.c
在这里插入图片描述
在这里插入图片描述
编译运行时agf 参数已经没有用了,但是还是要保留着,因为应用程序会判断参数个数对不对:
在这里插入图片描述

宽字符

代码为03.freetype\01th_pc\03th_wchar中的example1.c

想要显示一个汉字的时候还要去找它的 unicode 码,这样太麻烦了。能不能在程序里像如下这种方式写我想要的汉字:
在这里插入图片描述
这是不可以的。原因是对于汉字这种字符我们用两个字节表示,对于英文字母我们用一个字节显示。这样在处理字符的时候就要区别是汉字还是英文字母,处理起来麻烦。

引入了宽字符:宽字符中汉字个用 4 个字节表示,英文字母也用 4 个字节表示: 以后我们处理过程就会非常的方便。
在这里插入图片描述
宽字符的头文件:
在这里插入图片描述
定义一个宽字符:
在这里插入图片描述
03.freetype\01th_pc\03th_wchar中的example1.c进行编译运行:

错误为:无法转换字符集。

这里需要指定字符集:源代码 example1.c 是以ASCII码保存的。
在这里插入图片描述
编译时指定输入输出字符集:

gcc -finput-charset=GBK -fexec-charset=UTF-8 -o example1 example1.c -I/usr/local/include/freetype2 -lfreetype –lm

运行:打印出了 韦东山 gunicode 码:
在这里插入图片描述
拖到 ubuntu 编译:
在这里插入图片描述
运行出现段错误:Segmentation fault (core dumped)
在这里插入图片描述
text,num_chars 那一行注释掉:
在这里插入图片描述
再次编译运行:
在这里插入图片描述

深入理解

我们在源代码 example1.c 里指定了从(0,40)这个坐标开始打印文字。
在这里插入图片描述
03.freetype\01th_pc\04th_print_info中的example1.c拖到 ubuntu 编译,运行:
在这里插入图片描述
但是上述的结果却不是在(0,40)位置显示字符的。

在描画一个字符的时候要指定一个原点 origin,原点这条线称为基线字符有可能会超过基线
在这里插入图片描述
汉字不会超过基线,但是英文字母会超过基线:
在这里插入图片描述
在代码中:
在这里插入图片描述
打印xMin , xMax , yMin , yMax :
在这里插入图片描述
freetype-doc-2.4.10\freetype-2.4.10\docs\tutorial 里的 step2.html
在这里插入图片描述
搜索 cbox :
在这里插入图片描述
03.freetype\01th_pc\04th_print_info中的example1.c放在ubuntu下编译运行:

编译:gcc -finput-charset=GBK -fexec-charset=UTF-8 -o example1 example1.c  -I /usr/local/include/freetype2 -lfreetype -lm
运行:./example1 ./simsun.ttc abc	

显示:
在这里插入图片描述
往上翻找到打印信息:
在这里插入图片描述
根据上面的打印参数作下面的画:
在这里插入图片描述
如果实验中不显示"韦gif"的话,要把 串口工具的字体调小一点:
在这里插入图片描述

3.3、在LCD上显示字符

上一节,将字符打印到标准输出上的流程如下:

  • 1、从main函数开始,先初始化FT_Init_FreeType
  • 2、打开一个字体文件,得到一个face(平面);
  • 3、设置字体的大小;
  • 4、设置转换矩阵、参数;
  • 5、FT_Load_Char函数会根据字符的uniocde码在字体文件中得到glyph,其中参数FT_LOAD_RENDER指定将glyph转换为位图,之后就可以打印出字符了;
  • 6、使用draw_bitmap函数打印,将点阵存在全局数组中,使用show_image打印到标准输出

现在要想把字符打印到LCD,在draw_bitmap函数中将点阵信息存到LCD显存framebuf显存中即可。
在这里插入图片描述
根据说明文档交叉编译freetype库:
在这里插入图片描述
需要三步:

A: ./configure
B: make
C: make install

编译:

tar xjf freetype-2.4.10.tar.bz2 
cd freetype-2.4.10
./configure --host=arm-linux
su root	// 不切换的话会出错 https://www.veryarm.com/41852.html 
make DESTDIR=$PWD/tmp install	//表示编译出来的程序是在 arm 开发板 linux 下面使用

编译出来的头文件应该放入:

/usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include

编译出来的库文件应该放入:

/usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib

tmp/usr/local/lib/* 库文件复制到 /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib

//-d表示原来是链接文件,就保持链接文件 -rf表示全部都copy
sudo cp * /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib -d -rf
cp *so* /work/nfs_root/fs_mini_mdev_new/lib -d	//动态库拷贝到网络根文件系统

tmp/usr/local/include/* 头文件复制到 /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include

cp * /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include -rf

去掉 freetype2 这一层

cd /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include
mv freetype2/freetype .

编译example1.c

arm-linux-gcc -finput-charset=GBK -o example1 example1.c  -lfreetype -lm

拷贝到开发板:

cp example1 simsun.ttc /work/nfs_root/fs_mini_mdev_new/

运行example1
在这里插入图片描述
打印字体:
在这里插入图片描述
在这里插入图片描述
同样一个应用程序,在 PC 机上可以执行,交叉编译之后,在开发板上也可以执行。

3.4、在 LCD 上面显示矢量字体

不在这个控制台(开发板的串口窗口)上输出,在 LCD 上面输出时,由于之前第二节有在LCD上显示一个字符,只不过这个字符不能变化大小旋转等等、所以引入了freetype,现在只要把第二节中的show_font.c和我们example1.c结合就可以实现在LCD上显示矢量字体了。

修改03.freetype\02th_arm\02th_lcdshow_font.c
删除代码中无法识别的字符:
在这里插入图片描述
在这里插入图片描述

改为:
在这里插入图片描述
在这里插入图片描述
转换字符集:

iconv -f GBK -t UTF-8 show_font.c

编译:

arm-linux-gcc -finput-charset=GBK -fexec-charset=GBK -o show_font show_font.c -lfreetype -lm 

注意:这里输入是国标码,输出是国标码是指下图中str里存的时候输入文件里是国标码,当编译出应用程序时 str 里面存的也是国标码在这里插入图片描述
下图中输入是国标码,但是在宽字符串 chinese_str 里面存储的是宽字符的类型,宽字符的类型里面存的就是 unicode 码
在这里插入图片描述
将应用程序拷贝到网络根文件系统,在开发板上运行:

cp show_font /work/nfs_root/fs_mini_mdev_new
./show_font ./simsun.ttc

在这里插入图片描述

3.5、在 LCD 上面显示文字并显示一个角度

代码为03.freetype\02th_arm\03th_lcd_angle中的show_font.c

编译:

arm-linux-gcc -finput-charset=GBK -fexec-charset=GBK -o show_font show_font.c -lfreetype -lm 

将应用程序拷贝到网络根文件系统:

cp show_font /work/nfs_root/fs_mini_mdev_new

在开发板上运行:

./show_font ./simsun.ttc 0	//旋转角度45、90、180、270

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.6、在 LCD 上显示多行文字

从左边开始显示一行文字

代码为03.freetype\02th_arm\04th_show_one_line里的show_lines.c
在这里插入图片描述
文件中这些宽字符文字输入时是以国标码输入的,文件里面是以国标码存储的,但是在编译出来的程序是以宽字符类型 wchar_t 存储的,宽字符类型 wchar_t 里面存储的是 unicode 码

编译、拷贝、运行:

编译:arm-linux-gcc -finput-charset=GBK -fexec-charset=GBK -o show_font show_font.c -lfreetype -lm 
拷贝:cp show_font /work/nfs_root/fs_mini_mdev_new
运行:./show_font ./simsun.ttc 0	//旋转角度45、90、180、270

在这里插入图片描述
百字前面有空子的问题可能是 LCD 的驱动程序没有调整好水平方向的时序。

从左边开始显示两行文字

代码为03.freetype\02th_arm\05th_show_two_lines中的show_lines.c

字符的位置:
在这里插入图片描述
计算方框:
在这里插入图片描述
显示在LCD上:
在这里插入图片描述
编译、拷贝、运行:

编译:arm-linux-gcc -finput-charset=GBK -fexec-charset=GBK -o show_lines show_lines.c -lfreetype -lm 
拷贝:cp show_font /work/nfs_root/fs_mini_mdev_new
运行:./show_lines ./simsun.ttc 

在这里插入图片描述

居中显示两行文字

代码为03.freetype\02th_arm\06th_show_lines_center中的show_lines.c,显示坐标:
在这里插入图片描述
拖到 ubuntu 编译:
在这里插入图片描述
定位到第 158 行:
在这里插入图片描述
改为:
在这里插入图片描述
再拖到 ubuntu 编译:
在这里插入图片描述
定位到第 218 行:glyphconflict冲突
在这里插入图片描述
改为:
在这里插入图片描述
编译、拷贝、运行:

编译:arm-linux-gcc -finput-charset=GBK -fexec-charset=GBK -o show_lines show_lines.c -lfreetype -lm 
拷贝:cp show_font /work/nfs_root/fs_mini_mdev_new
运行:./show_lines ./simsun.ttc 

在这里插入图片描述
freetype 的使用简单地介绍到这里,如果想深究 freetype 里函数的用法,可以查看 freetype-2.4.10\docs\reference 目录里的函数说明文档。

如果不想看 freetype-2.4.10\docs\reference 目录里的那么多文档的话,可以看看 freetype 自带的文档 freetype-doc-2.4.10\freetype-2.4.10\docs\tutorial 目录里的 step1.html、step2.html,里面讲解的非常清楚。

如果英文不好的话,也可以查看网上别人翻译好的中文版:FreeType 字体引擎分析与指南

4、参考资料

FreeType 字体引擎分析与指南

HZK16应用示例

点阵字库HZK12 HZK16 HZK24 ASC12 ASC16 简介 及 使用方法

汉字拼音、五笔、GB2312、GBK、Unicode、BIG5编码速查

在线汉字编码查询,一次查询多个汉字输入法编码及内码——快典网.htm

BIG5编码表

UNICODE编码表

GB2312简体中文编码表

hzk16的介绍以及简单的使用方法

UTF-8

getopt的用法

上一节:1、数码相框之框架分析

下一节:3、数码相框之电子书

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
这份文档提供了FreeType 2函数库设计与实现的细节。本文档的目标是让开发人员更好的理解FreeType 2是如何组织的,并让他们扩充、定制和调试它。 首先,我们先了解这个库的目的,也就是说,为什么会写这个库: * 它让客户应用程序方便的访问字体文件,无论字体文件存储在哪里,并且与字体格式无关。 * 方便的提取全局字体数据,这些数据在平常的字体格式中普遍存在。(例如:全局度量标准,字符编码/字符映射表,等等) * 方便的提取某个字符的字形数据(度量标准,图像,名字,其他任何东西) * 访问字体格式特定的功能(例如,SFNT表,多重控制,OpenType轮廓表) Freetype 2的设计也受如下要求很大的影响: * 高可移植性。这个库必须可以运行在任何环境中。这个要求引入了一些非常激烈的选择,这些是FreeType2的低级系统界面的一部分。 * 可扩展性。新特性应该可以在极少改动库基础代码的前提下添加。这个要求引入了非常简单的设计:几乎所有操作都是以模块的形式提供的。 * 可定制。它应该能够很容易建立一个只包含某个特定项目所需的特性的版本。当你需要集成它到一个嵌入式图形库的字体服务器中时,这是非常重要的。 * 简洁高效。这个库的主要目标是只有很少cpu和内存资源的嵌入式系统。 这份文档的其他部分分为几个部分。首先,一些章节介绍了库的基本设计以及Freetype 2内部对象/数据的管理。 接下来的章节专注于库的定制和与这个话题相关的系统特定的界面,如何写你自己的模块和如何按需裁减库初始化和编译。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

「已注销」

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值