【震惊】“贫穷”的MCU中居然可以定制UTF8编码的TTF小字库?

文摘   2023-11-14 21:26   英国  

【说在前面的话】


随着成本的降低,很多嵌入式产品都有能力配备一块适当大小的彩色屏幕——不仅看起来更智能,也更容易走出国门、迈向世界——撬动中高端市场。那么,在成本压力下,一些小资源的设备如何支持多国语言文字呢?
Arm-2D 提供了一个简单的方案。

【什么是UTF-8 编码】


让智能设备支持各国不同的文字,首先得有支持全球文字的编码集,时下最出名的要数UTF-8码了。它一种可变长度字符编码,使用1~4字节为每个字符编码,由此它可以用来表示Unicode标准中的任何字符,而且仍与ASCII码相兼容。
有了国际范的UTF-8码,如果我们再有一个支持UTF-8码的字库,那显示各国的文字就很简单了。接下来就讲一下怎么制作一个支持UTF-8码的字库(然这个并不是包含所有的字符,而是只覆盖所需的就可以了)


【如何制作 UTF-8 编码的小字库】


要制作字库,肯定是要找一个现成的取模工具了(这种工具网上有很多),今天我们就使用Arm-2D提供的一个python小工具来制作UTF-8码的字库,下载最新的Arm-2D,你就会看到在Acceleration下有一个ttf2c.py文件,如下图

有了这个工具,我们就看看怎么使用它来制作字库文件。

【准备工作】

首先,你的电脑中要安装了Python3,并且安装了下面两个软件包(freetype-py和numpy)

pip install freetype-pypip install numpy

然后从网上或者电脑C:\Windows\Fonts文件夹下找到一个后缀名为TTF的字体文件,如下

制作字库

接下来就用ttf2c.py制作字库,它的使用在官方文档中也有,如下

当然,你也可以用【-h】指令来查看它的使用方法,如下图

我们使用的指令为:

python3 ttf2c.py -h

这里

  • -i”    为后缀TTF文件

  • -t”    为txt文件,里面为我们要生成字库的所有字符

  • -n” 我们生成的字库起名字,如果省略默认名称为ARM_2D_FONT_UTF8。一般推荐用 字体名称+像素尺寸 来命名,比如:ARIAL24

  • -o”    就是输出的字库文件

  • -p”   为字体的像素尺寸(比如24、32等等)

  • -s”   指定生成字库的格式,可以为A1(也就是点阵字库)、A2、A4、和A8。如果省略该参数,将生成所有的格式。其中A1所占的flash空间是最小的,A2、A4、A8还支持字体透明度哦。一般情况下,考虑到没用到的字体格式会被编译器Linker丢弃,所以推荐直接省略该参数



如果你还不知道什么是A1、A2、A4、A8字体,可以看看下面这篇文章《【玩转arm-2d】手把手教你实现抗锯齿的字体



接下来我们就可以使用ttf2c.py来生成一个字库试试。首先新建一个txt文件(比如 cc.txt),输入我们要生成字库的所有字符,如下

在cc.txt文件中输入的字符为“嵌入式小书虫”,待会就会生成对应的字库文件。

生成字库的指令如下:

python3 ttf2c.py -i SIMYOU.TTF -t cc.txt -o ./qrsxsc.c

此时就会生成字库文件qrsxsc.c,如下图

有了字库文件,显示字符就很简单了。

【显示UTF-8码的文字】

【如何使用生成的UTF-8小字库】


使用Arm-2D来显示自定义字库中的文字非常简单。首先在生成的.c中找到对应字体类型的声明,将其拷贝到要使用字库的C源代码文件中(别忘记加入extern),以A8为例如下所示:
extern struct {    implement(arm_2d_user_font_t);    arm_2d_char_idx_t tUTF8Table;} ARM_2D_FONT_UTF8_A8;

然后就可以使用这个字库啦(* ̄︶ ̄),很简单,代码如下

arm_lcd_text_set_font(&ARM_2D_FONT_UTF8_A8);arm_lcd_text_set_draw_region(NULL);arm_lcd_text_set_colour(GLCD_COLOR_GREEN, GLCD_COLOR_WHITE);arm_lcd_text_location(1,1); arm_lcd_text_set_opacity(120);   arm_lcd_printf("嵌入式小书虫");
  • 第1行就是设置我们的字库

  • 第2行为设置字符显示的区域,NULL为整个屏幕

  • 第3行为设置字体颜色

  • 第4行为设置在第几行第几列进行显示字符

  • 第5行为设置字体的透明度

  • 最后调用arm_lcd_printf函数就可以了


注意:此时,把程序下载进去,可能屏幕不会显示“嵌入式小书虫”这几个字哦!

这是因为我们的字库是UTF-8编码的,而你在keil MDK中可能设置的是GB2312编码集哦,所以当屏幕没有显示出我们想要的字符时,要记得修改一下编码集,如下

点击小扳手进行设置,如下

好了,这样屏幕中就可以显示我们的字符了。接下来再讲一下怎么显示中英文切换,今天的重点就是这个哦。视频演示如下

看起来很简单,但是值得一说的是我们使用了Arm-2D提供的arm_lcd_print_banner()函数,它可以方便我们在指定的区域内居中显示字符串,如下图

程序如下

enum {    LANGUAGE_ID_ENGLISH,    LANGUAGE_ID_CHINESE};arm_2d_region_t myRegions={    .tLocation = {        .iX = 50,        .iY = 106,    },    .tSize = {        .iWidth = 92,        .iHeight = 30,    },};
if (LANGUAGE_ID_CHINESE == language) { arm_lcd_print_banner("雷阵雨",myRegions,&ARM_2D_FONT_UTF8_A8);} else { arm_lcd_print_banner("thunderstorm",myRegions,&ARM_2D_FONT_UTF8_A8);}
  • 第1个参数就是要显示的字符串

  • 第2个参数为字符串显示的区域

  • 第3个参数就是要使用的字体

怎么样,使用还是很简单吧,O(∩_∩)O哈哈~

其实arm_lcd_print_banner()还有2个不同的版本(不同的参数)哦!

如果我们已经设置好了字体,第3个参数是可以省略的,如下

arm_lcd_print_banner("雷阵雨",myRegions);

如此,上面的代码也可以改写成这样,如下

arm_lcd_text_set_font((arm_2d_font_t*)&ARM_2D_FONT_UTF8_A8);if(LANGUAGE_ID_CHINESE == language){    arm_lcd_print_banner("雷阵雨",myRegions);}else{    arm_lcd_print_banner("thunderstorm",myRegions);}

同样的,第二个参数也可以省略,如下

arm_lcd_print_banner("雷阵雨");

那这个只有一个参数,没有设置区域,它会在哪里居中呢?

哈哈,此时如果只传一个参数,它就会默认在屏幕中间显示字符串

是不是觉得arm_lcd_print_banner()这个函数就是专门为支持各国不同的文字量身定做的,使我们可以轻松实现多国语言的切换(* ̄︶ ̄)

当然,使用很简单,那是因为Arm-2D都为我们制作好了,其实TTF字体里面还有很多Bearing(字体大小、水平预留值等),如下图

这些Arm-2D都为我们做好了,感兴趣的可以看源码哈(* ̄︶ ̄),这里我们就不讲了。

还有一个关于字符显示的API函数需要简单介绍一下,就是提取一行字符串尺寸的函数,如下
arm_2d_size_t StringSize     = arm_lcd_get_string_line_box(          "雷阵雨",          &ARM_2D_FONT_UTF8_A8);

arm_lcd_get_string_line_box()这个函数可以帮我们计算出目标字体在给定字符串下的单行尺寸——这样就可以精确控制字符串位置、方便进行对齐。实际上在arm_lcd_print_banner()就使用了此函数,它的妙用还期待大家进行开发(* ̄︶ ̄)

对了,大家有没有发现,视频中的闪电有一个不错的呼吸效果,这个是如何实现的呢?

其实这个还是用了上一篇文章讲过的知识,使用了arm_2d_helper_time_cos_slider(),程序如下
uint8_t opacity = 0;static void __on_scene0_frame_start(arm_2d_scene_t *ptScene){
    int32_t iResult;                               arm_2d_helper_time_cos_slider(0, 255, 2000, 0, &iResult, &lTimestamp2); opacity = iResult;
}
  • frame_start函数中调用,使iResult的取值按照cos函数变化,其取值范围为0~255,然后赋值给opacity,使闪电图片的透明度按照cos曲线变化

  • 最后在绘制函数中按照计算出来的透明度进行绘制就可以了,如下:

 arm_2dp_rgb565_tile_copy_with_colour_keying_and_opacity(         NULL,         &c_tilerain4RGB565,          ptTile,         &myRegions,      /* 图标显示位置 */         opacity,         /* 透明度 */                                   (arm_2d_color_rgb565_t){GLCD_COLOR_BLACK}    );


【说在后面的话】


好了,到这里今天的内容就讲完了。欢迎大家和我一起玩转Arm-2D,我们的口号是:一起玩,一起玩才更好玩。下期精彩继续(任意弧度的圆环进度条)。。。


原创不易,如果你喜欢我的公众号、觉得我的文章对你有所启发,

请务必“点赞、收藏、转发”,这对我很重要,谢谢!

欢迎订阅    嵌入式小书虫

裸机思维
傻孩子图书工作室。探讨嵌入式系统开发的相关思维、方法、技巧。
 最新文章