关于Simple GUI精简字库的制作方法

关于Simple GUI精简字库的制作方法

SimpleGUI

简介

SimpleGUI是一款针对单色显示屏设计的GUI开源接口库,simpleGUI提供了列表组件、2d画图组件、文本组件、位图组件、滚动条组件等。

在这里插入图片描述

Simple GUI开源地址:https://gitee.com/Polarix/simplegui

字库基础知识

本文章针对Simple GUI 的文本接口方面的知识进行分析。字库是Simple GUI 的文本接口文本接口的一个知识点。(本知识点引用作者的帮助文档)

1. 字体和字号

  在计算机中,所有显示在屏幕上的东西,包括文字在内,都是被像素化过后的图形,相比基本的平面几何图形或3D图形的随机和不可预见,文字是一种特殊的、有规律、有局限的图形如果不考虑文字的大小,那么每一个文字在同一种字体中,只对应一个图形。
  至于字体,就是一个文字的不同形体,再简单点儿说,就是字的写法,就如同“文”字,在宋体、黑体、楷体中的字形式完全不同的,而字体文件就是文字在同一字体下的集合文件。计算机可以通过字符编码,在字体文件中找到对应的文字图形并显示,用户就在屏幕上看到“人”可以理解的文字了。
  至于字号,表达的就是一个字符的大小了,这个量本身和字体并没有关系。

2. 编码与解码

  字符编码简称字码,指用特定的数字表示对应字符的一种索引方式。
  前文对字体文件的描述,字体文件中通常包含了该字体下大部分常用字的图形信息,那么如何索引对应的图形,就是文字编码的意义所在。

3.1. ASCII编码

  ASCII编码的历史基本和电子计算机的历史一样长,全名为American Standard Code for Information Interchange,中文译为“美国(国家)信息交换标准码”,此种编码使用七个二进制位表达字一个字符,最多表达128个字符,其中可见字符96个,控制字32个。
  后来由于ASCII不太够用,国际标准化组织又制定了 ISO2022 标准,它将ASCII字符集扩充为8位代码,后续又制定了一批适用于不同地区的扩充ASCII字符集,每种扩充ASCII字符集分别可以扩充128个字符,这些扩充字符的编码均为高位为1的8位代码,称为扩展ASCII码。
  拓展ASCII码现在使用并不太多,在此不作详述。

3.2. ANSI编码

  为了扩充ASCII编码,以用于显示本国的语言,不同的国家和地区制定了不同的标准,由此产生了针对不同国家的不同的编码标准,称为ANSI,全名American National Standards Institute Code,中文译为“美国国家标准学会编码”,又称为MBCS,全称又称为“Muilti-Bytes Charecter Set”,中文译为“多字节字符集”。这些标准使用2个字节来代表一个基本ASCII码以外的字符,高位字节的高位必然为1,用于和基本ASCII码区别。换而言之,ANSI并不是一种编码,而是一类编码,在上世纪90年代,有些从国外引入的(尤其是从日本引入的)电子游戏运行时产生乱码就是因为这个原因,虽然同为ANSI,但是不同国家和地区使用的编码和对照的字符表完全不同。这也就催生了诸如“南极星”、“东方快车”之类的转码软件。
  中文常用的ANSI编码有GB2312、GBK、GB10801等,各个编码的详细信息在上网搜索均有大量说明,在此不再详述。

3.5. GB2312的编码与解码

  GB2312是中国大陆地区常用的中文编解码方式。GB2312编码也属于变长编码,基本ASCII字符为0~127,占用一字节,基本ASCII以外的字符均以2字节表达,且每字节高位均为1。
  GB2312的非ASCII字符包括制表符、带圈数字、全角标点、全角英文字母、俄文字母、日语平假名、日语片假名、以及汉字6763个,其中一级汉字3755个,二级汉字3008个。其中一级汉字即我们俗称的常用字,如果是制作嵌入式字库,那么通常情况下汉字只包含一级汉字即可。
  GB2312编码表达汉字分为“页”和“码”两部分,高位字节为“页码”,低位字节为“字码”,页码分为两大部分,高四位为十六进制A的(0xAXXX)为符号,高四位为十六进制B~F的(0xBXXX~0xFXXX)为汉字,具体分配如下:

页号页码表达内容
01~09A1~A9特殊符号,包括全角拉丁字母、日语假名、俄文西里尔字母等。
10~15AA~AF保留区,没有使用。
16~55B0~D7一级汉字。
56~87D8~F7二级汉字。
88~94F8~FE保留区,没有使用。

  需要注意的是,GB2312的每一页都是没有用满的,通常第一位留白,最后一位留白,其他的我还没有找到规律。例如GB2312编码的第一个汉字是“啊”,编码是十六进制的B0A1,而B0A0是空白的。

3.4. Unicode编码

  由于ANSI无法表达特定的编码,在跨地域时乱码的问题几乎无可避免,这就催生了Unicoed,这种一个联合编码集,意在使用一个字符集表达世界上所有语言所包含的所有书面符号(甚至是同一汉字的不同写法,如“户”和“戸”等),且每一个符号都有自己唯一的编码,这样一来,乱码的问题就迎刃而解了。
  Unicode码使用3字节的长度表达一个字符,最高字节为平面(Panel)索引,范围为0x000x10(十进制17),低两字节为字符码,表达范围为065535。也就是说,Unicode编码的表达范围为0x000000~0x10FFFF。
  其他Unicode编码的细节,网上有详细介绍,不作详述。

3.5. UTF-8的编码与解码

  UTF-8编码更准确的说,应该属于字符串编码而非字符编码,因为他规定的是一个Unicode字符在字符串中的表达形式。
  Unicode编码为全世界所有语言的所有字符提供了兼容的解决方案,但是如何合理的使用才是真正的难题,如果直接使用Unicode编码,那么相比ASCII,每个字符都要由1字节型变成4字节型,高位以0补齐,如果文本文件为纯英文,那么内容不变的前提下,文件体积将增加三倍。
  然而这还不是最致命的,最致命的是文件编码的向下兼容问题。在ASCII编码下,字符串以一字节的0x00结尾,那么如果强制扩展到Unicode下,所有基本ASCII字符就都变成了0x000000XX这样,高三字节均为0x00,在逻辑上均视为字符串终止,这是不能接受的。
  于是,UTF-8编码,提供了一种同时兼顾“节约空间”和“向下兼容”的方式来表达Unicode编码,具体表达方式如下:

Unicode编码(HEX)UTF-8 字节流(BIN)
000000~00007F0XXXXXXX
000080~0007FF110XXXXX 10XXXXXX
000800~00FFFF1110XXXX 10XXXXXX 10XXXXXX
010000~10FFFF11110XXX 10XXXXXX 10XXXXXX 10XXXXXX

  由上可见,UTF-8提供了一种变长编码格式,忽略Unicode中高位字节为0x00的字节。
  在字符串中的解码方式为从第一个字节起,如果字节最高位为0,那么此字节表示一个基本ASCII字符,编码为当前字节的值,如果最高位为1,那么从最高位向低,遇到第一个0为止1的个数(至少为两个)表达字符占用的字节数(包括当前字节),后续字节均为10开头,那么取当前字节高位起第一个0之后的所有位以及后续特定数目字节的低六位(忽略开头的10),拼接在一起,即当前字符对应的Unicode码。
  依此规则,UTF-8格式的字符串就可以被逐一解析为Unicode编码,并最终索引到对应字符。

Simple GUI精简字库的制作方法

  中文支持固然好,但是对静态存储资源的消耗也相当可观,以SimpleGUI默认的12像素字体为例,每个半角字符需要消耗62字节,全角字符需要消耗122字节,那么整个GB2312字库对Flash的消耗为:

(6*2)*96+(12*2)*3755+(12*2)*682 = 53820 Bytes

  53KB的Flash消耗对于单片机来说还是非常可观的,这还仅仅包含了一级汉字,如果再加上二级汉字,那么还需要额外的7.2KB空间,如果还需要其他不同大小的字体,空间资源需求还要成倍增加,所以这种时候,通常就要使用外部字库了。
  但事实上,很多时候,界面上的文字都是既定好的,不需要动态的变化,这也就决定了整个系统中可能仅仅就需要使用少数的几个字符。这时候如果还要去设计外部字库显然对软硬件成本都是一种浪费,精简字库消耗才是正途。
  通过前文的说明,字符和字符串的编码,说到底不过就是从字符编码到字库索引上的一种算法表达,精简字库,说到底也是从这一方面着手,删除掉字库中用不到的文字和符号,重新定义编码和索引,字库的精简就完成了。
  基于以上思想,精简字库首先要列出整个目标系统中所有可能用到的文字,然后进行去重,提炼出目标系统中用到的所有汉字。然后给这些汉字进行重新编码,简而言之就是进行简单排序,然后重新编号,这个编号就是新规定的字符编码。最后,用这个新的编码重新去对字符串进行编码,这样就完成了字库的精简了。
  举个例子,假设我们要编写一个万年历,要求显示时间和二十四节气,那么可以预知,要显示的文字包括数字、半角冒号、大写数字、还有二十四节气的名字。需要用到的文字如下:

:1234567890
一二三四五六七八九十廿卅
年月日时分秒
立春
雨水
惊蛰
春分
清明
谷雨
立夏
小满
芒种
夏至
小暑
大暑
立秋
处暑
白露
秋分
寒露
霜降
立冬
小雪
大雪
冬至
小寒
大寒

  基本上要用的文字资源就这些了,然后对这些文字进行提炼,删除掉重复的文字,得到如下资源:

0123456789:
一七三九二五八六冬分十卅四处夏大寒小年廿惊日时明春暑月水清满白秋种秒立至芒蛰谷降雨雪霜露

  可以看到,删除掉重复文字后,内容明显少了很多,按照上述资源,对每一个文字进行重新编号,也就是编码,同时根据前文保持步进一致以方便数据寻址的原则,汉字等全角字符全部间隔一个编号,例如上述字符“0”编号为0x00,字符“:”编号为0x0A,字符“一”编号为0x800B,而字符七则编号为“0x800D”,中间跳过一个编码0x800C,此处为了区别半角与全角字符,所有非ASCII字符全部以0x80开头,占两字节。
  通过以上的编码操作,我们就可以再万年历系统中,对需要的字符串给出新的编码定义,例如立春,标准的GB2312编码应为:

0x33,0x02,0x20,0x26

  而依照我们自定义的新编码应为:

0x80,0x4F,0x80,0x3B 

  以此类推,其他23个节气的新编码分别为:

0x80,0x5B,0x80,0x41
0x80,0x33,0x80,0x55
0x80,0x3B,0x80,0x1D
0x80,0x43,0x80,0x39
0x80,0x57,0x80,0x5B
0x80,0x4F,0x80,0x27
0x80,0x2D,0x80,0x45
0x80,0x53,0x80,0x4B
0x80,0x27,0x80,0x51
0x80,0x2D,0x80,0x3D
0x80,0x29,0x80,0x3D
0x80,0x4F,0x80,0x49
0x80,0x25,0x80,0x3D
0x80,0x47,0x80,0x61
0x80,0x49,0x80,0x1D
0x80,0x2B,0x80,0x61
0x80,0x5F,0x80,0x59
0x80,0x4F,0x80,0x1B
0x80,0x2D,0x80,0x5D
0x80,0x29,0x80,0x5D
0x80,0x1B,0x80,0x51
0x80,0x2D,0x80,0x2B
0x80,0x29,0x80,0x2B

  反映到C语言代码中为:

{"\x80\x4F\x80\x3B"},  // 立春
{"\x80\x5B\x80\x41"},  // 雨水
{"\x80\x33\x80\x55"},  // 惊蛰
{"\x80\x3B\x80\x1D"},  // 春分
{"\x80\x43\x80\x39"},  // 清明
{"\x80\x57\x80\x5B"},  // 谷雨
{"\x80\x4F\x80\x27"},  // 立夏
{"\x80\x2D\x80\x45"},  // 小满
{"\x80\x53\x80\x4B"},  // 芒种
{"\x80\x27\x80\x51"},  // 夏至
{"\x80\x2D\x80\x3D"},  // 小暑
{"\x80\x29\x80\x3D"},  // 大暑
{"\x80\x4F\x80\x49"},  // 立秋
{"\x80\x25\x80\x3D"},  // 处暑
{"\x80\x47\x80\x61"},  // 白露
{"\x80\x49\x80\x1D"},  // 秋分
{"\x80\x2B\x80\x61"},  // 寒露
{"\x80\x5F\x80\x59"},  // 霜降
{"\x80\x4F\x80\x1B"},  // 立冬
{"\x80\x2D\x80\x5D"},  // 小雪
{"\x80\x29\x80\x5D"},  // 大雪
{"\x80\x1B\x80\x51"},  // 冬至
{"\x80\x2D\x80\x2B"},  // 小寒
{"\x80\x29\x80\x2B"},  // 大寒

  至此,经过统计字库大小由143文字精简至99文字(全角字符一个算两文字),实现了预期的精简字库的效果。
  同时,为了方便这个文字提取与重编码的操作,作者还编写了一个小工具MinimumFontLib,您可以访问码云上MinimumFontLib的托管页面获取该工具的可执行文件与源码。

  得到这些数据后我们还要制作字模。
使用PCtoLCD2002生成字模数据

//字模数组
const SGUI_CBYTE DEMO_H12[]={
0x00, 0xF8, 0x04, 0x04, 0x04, 0xF8, 0x00, 0x01, 0x02, 0x02, 0x02, 0x01,//"0",0
0x00, 0x00, 0x08, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x02, 0x00,//"1",1
0x00, 0x18, 0x84, 0x44, 0x24, 0x18, 0x00, 0x03, 0x02, 0x02, 0x02, 0x02,//"2",2
0x00, 0x08, 0x04, 0x24, 0x24, 0xD8, 0x00, 0x01, 0x02, 0x02, 0x02, 0x01,//"3",3
0x00, 0xC0, 0xA0, 0x98, 0xFC, 0x80, 0x00, 0x00, 0x00, 0x02, 0x03, 0x02,//"4",4
0x00, 0x7C, 0x24, 0x24, 0x24, 0xC4, 0x00, 0x01, 0x02, 0x02, 0x02, 0x01,//"5",5
0x00, 0xF0, 0x48, 0x24, 0x24, 0xC8, 0x00, 0x01, 0x02, 0x02, 0x02, 0x01,//"6",6
0x00, 0x00, 0x04, 0xC4, 0x34, 0x0C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,//"7",7
0x00, 0xD8, 0x24, 0x24, 0x24, 0xD8, 0x00, 0x01, 0x02, 0x02, 0x02, 0x01,//"8",8
0x00, 0x38, 0x44, 0x44, 0x24, 0xF8, 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,//"9",9
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,//":",10
0x20, 0x10, 0xFC, 0x03, 0xFC, 0x02, 0x81, 0xFC, 0x04, 0x04, 0xFC, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x03, 0x01, 0x00, 0x0F, 0x00, 0x02, 0x03, 0x00,//"仰",11
0x10, 0x10, 0x48, 0x84, 0x02, 0xF1, 0x02, 0x84, 0x48, 0x10, 0x10, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x0F, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00,//"伞",12
0x10, 0xFC, 0x03, 0x00, 0xFA, 0xAA, 0xAF, 0xAA, 0xAA, 0xFA, 0x02, 0x00, 0x00, 0x0F, 0x00, 0x08, 0x0F, 0x0A, 0x0A, 0x0A, 0x0A, 0x0F, 0x08, 0x00,//"值",13
0x40, 0x48, 0x49, 0x4A, 0x48, 0xF8, 0x48, 0x4A, 0x49, 0x48, 0x40, 0x00, 0x08, 0x08, 0x04, 0x02, 0x01, 0x00, 0x01, 0x02, 0x04, 0x08, 0x08, 0x00,//"关",14
0x84, 0x45, 0xF6, 0x4C, 0xA0, 0x02, 0xFE, 0x02, 0x02, 0x02, 0xFE, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x08, 0x06, 0x01, 0x00, 0x08, 0x08, 0x07, 0x00,//"初",15
0x08, 0x08, 0xFF, 0x08, 0x08, 0xF8, 0x00, 0xFC, 0x04, 0x04, 0xFC, 0x00, 0x08, 0x06, 0x01, 0x08, 0x08, 0x07, 0x00, 0x0F, 0x04, 0x04, 0x0F, 0x00,//"加",16
0x90, 0x54, 0xB6, 0x95, 0x5C, 0x54, 0x34, 0x94, 0x36, 0x54, 0x90, 0x00, 0x00, 0x0A, 0x0A, 0x0A, 0x0A, 0x09, 0x05, 0x04, 0x04, 0x02, 0x00, 0x00,//"参",17
0x0E, 0x08, 0x88, 0x78, 0xCF, 0x48, 0x48, 0x49, 0xCA, 0x08, 0x08, 0x00, 0x04, 0x02, 0x09, 0x08, 0x04, 0x05, 0x02, 0x05, 0x04, 0x08, 0x08, 0x00,//"发",18
0x00, 0x00, 0xFE, 0x12, 0x92, 0x92, 0x92, 0x91, 0x91, 0x91, 0x90, 0x00, 0x08, 0x06, 0x01, 0x00, 0x0F, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0F, 0x00,//"后",19
0x00, 0x00, 0xFC, 0xA4, 0xA4, 0xA5, 0xA6, 0xA4, 0xA4, 0xA4, 0xBC, 0x00, 0x08, 0x06, 0x01, 0x0F, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0F, 0x00,//"启",20
0x84, 0x44, 0xE4, 0x1C, 0x07, 0x84, 0x84, 0xF4, 0x84, 0x84, 0x04, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x08, 0x08, 0x08, 0x0F, 0x08, 0x08, 0x08, 0x00,//"在",21
0x88, 0x78, 0x0F, 0xF8, 0x00, 0xD8, 0x54, 0x53, 0x50, 0xD8, 0x30, 0x00, 0x08, 0x05, 0x02, 0x0D, 0x00, 0x0F, 0x04, 0x04, 0x04, 0x0F, 0x00, 0x00,//"始",22
0x00, 0xFE, 0x0A, 0x8A, 0xBE, 0xAA, 0xAB, 0xAA, 0xBE, 0x8A, 0x0A, 0x00, 0x08, 0x07, 0x00, 0x08, 0x09, 0x0A, 0x04, 0x04, 0x0A, 0x09, 0x08, 0x00,//"度",23
0x02, 0x32, 0x2A, 0xE6, 0x00, 0xF2, 0x02, 0x02, 0xFE, 0x21, 0x21, 0x00, 0x08, 0x05, 0x02, 0x05, 0x08, 0x0B, 0x0A, 0x0A, 0x0B, 0x0A, 0x0A, 0x00,//"延",24
0x40, 0x42, 0x42, 0xFE, 0x42, 0x42, 0x42, 0xFE, 0x42, 0x42, 0x40, 0x00, 0x00, 0x08, 0x06, 0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00,//"开",25
0x08, 0x48, 0x48, 0xC8, 0x48, 0x48, 0x08, 0xFF, 0x08, 0x09, 0x0A, 0x00, 0x08, 0x08, 0x08, 0x07, 0x04, 0x04, 0x04, 0x00, 0x03, 0x04, 0x0E, 0x00,//"式",26
0x04, 0x24, 0x24, 0x24, 0x24, 0xBF, 0x24, 0x24, 0x24, 0x24, 0x04, 0x00, 0x04, 0x03, 0x00, 0x07, 0x08, 0x08, 0x0B, 0x08, 0x0C, 0x01, 0x06, 0x00,//"志",27
0x00, 0x7C, 0x45, 0x46, 0x44, 0x44, 0x44, 0x46, 0x45, 0x7C, 0x00, 0x00, 0x08, 0x06, 0x00, 0x06, 0x08, 0x09, 0x0A, 0x08, 0x0C, 0x01, 0x06, 0x00,//"总",28
0x88, 0x88, 0xFF, 0x48, 0x48, 0x02, 0x02, 0x02, 0xFE, 0x02, 0x02, 0x00, 0x00, 0x08, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x08, 0x0F, 0x00, 0x00, 0x00,//"打",29
0x88, 0x88, 0xFF, 0x48, 0x00, 0x4C, 0xC4, 0x75, 0x46, 0xC4, 0x4C, 0x00, 0x00, 0x08, 0x0F, 0x00, 0x08, 0x08, 0x05, 0x02, 0x02, 0x05, 0x08, 0x00,//"按",30
0x44, 0xFB, 0x4A, 0x6A, 0x4A, 0xFA, 0x50, 0xEF, 0x08, 0xF8, 0x08, 0x00, 0x00, 0x03, 0x02, 0x0B, 0x0A, 0x07, 0x0A, 0x05, 0x02, 0x05, 0x08, 0x00,//"敏",31
0x48, 0x2A, 0x98, 0x7F, 0x28, 0x4A, 0x10, 0xEF, 0x08, 0xF8, 0x08, 0x00, 0x09, 0x0B, 0x05, 0x05, 0x0B, 0x00, 0x08, 0x05, 0x02, 0x05, 0x08, 0x00,//"数",32
0x00, 0xFE, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xFE, 0x00, 0x00, 0x00, 0x0F, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0F, 0x00, 0x00,//"日",33
0xFE, 0x22, 0x22, 0xFE, 0x00, 0x08, 0x48, 0x88, 0x08, 0xFF, 0x08, 0x00, 0x07, 0x02, 0x02, 0x07, 0x00, 0x00, 0x00, 0x09, 0x08, 0x0F, 0x00, 0x00,//"时",34
0x88, 0x68, 0xFF, 0x28, 0x40, 0xFE, 0x02, 0x02, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x08, 0x04, 0x03, 0x00, 0x00, 0x07, 0x08, 0x0E, 0x00,//"机",35
0x88, 0x68, 0xFF, 0x48, 0x02, 0xFA, 0xAF, 0xAA, 0xAF, 0xFA, 0x02, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x0A, 0x0A, 0x06, 0x03, 0x06, 0x0A, 0x0A, 0x00,//"模",36
0x00, 0x22, 0xAA, 0x2A, 0x2A, 0xEA, 0x2A, 0x2A, 0x2A, 0xBE, 0x00, 0x00, 0x08, 0x09, 0x04, 0x04, 0x02, 0x01, 0x02, 0x04, 0x05, 0x08, 0x08, 0x00,//"灵",37
0x10, 0x17, 0xD5, 0x55, 0x57, 0x7D, 0x57, 0x55, 0xD5, 0x17, 0x10, 0x00, 0x08, 0x08, 0x0F, 0x08, 0x08, 0x0E, 0x08, 0x08, 0x0F, 0x08, 0x08, 0x00,//"置",38
0x20, 0xFE, 0xAB, 0xFE, 0x00, 0x0C, 0xE4, 0x05, 0x86, 0x44, 0x2C, 0x00, 0x08, 0x07, 0x08, 0x0F, 0x00, 0x00, 0x07, 0x09, 0x08, 0x08, 0x0E, 0x00,//"舵",39
0x0E, 0xE0, 0x20, 0x3F, 0x20, 0xA8, 0x27, 0x22, 0x26, 0xEA, 0x02, 0x00, 0x08, 0x09, 0x04, 0x04, 0x02, 0x01, 0x06, 0x08, 0x08, 0x09, 0x0C, 0x00,//"览",40
0x08, 0xF4, 0x53, 0x52, 0x52, 0xF2, 0x5A, 0x56, 0x50, 0xF0, 0x00, 0x00, 0x08, 0x07, 0x01, 0x01, 0x01, 0x07, 0x01, 0x01, 0x09, 0x0F, 0x00, 0x00,//"角",41
0xF4, 0x53, 0xFA, 0x56, 0xF0, 0x00, 0xF8, 0x88, 0xFF, 0x88, 0xF8, 0x00, 0x07, 0x01, 0x07, 0x09, 0x0F, 0x00, 0x08, 0x08, 0x0F, 0x04, 0x0E, 0x00,//"触",42
0x10, 0x11, 0xF2, 0x00, 0x50, 0xCF, 0x41, 0x41, 0x4F, 0xD0, 0x10, 0x00, 0x00, 0x00, 0x07, 0x02, 0x08, 0x08, 0x05, 0x02, 0x05, 0x08, 0x08, 0x00,//"设",43
0x11, 0xF2, 0x00, 0x7A, 0x4A, 0xCA, 0xFF, 0xCA, 0x4A, 0x7A, 0x02, 0x00, 0x08, 0x07, 0x08, 0x0A, 0x09, 0x08, 0x0F, 0x08, 0x09, 0x0A, 0x08, 0x00,//"速",44
0x08, 0xFF, 0xA9, 0xA9, 0xA9, 0xFB, 0xAD, 0xA9, 0xA9, 0xFF, 0x08, 0x00, 0x08, 0x0A, 0x0A, 0x0A, 0x0A, 0x0F, 0x0A, 0x0A, 0x0A, 0x0A, 0x08, 0x00,//"量",45
0x20, 0x20, 0x20, 0xFF, 0x28, 0x28, 0xE4, 0x24, 0x22, 0x22, 0x20, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x04, 0x02, 0x00, 0x01, 0x02, 0x04, 0x04, 0x00,//"长",46
0xF9, 0x02, 0xE8, 0x29, 0xE9, 0x09, 0xFF, 0x09, 0xCB, 0x01, 0xFF, 0x00, 0x0F, 0x00, 0x05, 0x05, 0x0B, 0x04, 0x03, 0x05, 0x0E, 0x08, 0x0F, 0x00,//"阈",47
0x20, 0x2A, 0xF2, 0x2E, 0x60, 0x00, 0xF2, 0x1A, 0xD6, 0x12, 0xF2, 0x00, 0x00, 0x08, 0x0F, 0x00, 0x00, 0x00, 0x09, 0x04, 0x03, 0x04, 0x09, 0x00,//"预",48
0x82, 0x82, 0xBA, 0xAA, 0xAA, 0xAB, 0xAA, 0xAA, 0xBA, 0x82, 0x82, 0x00, 0x0F, 0x00, 0x00, 0x0E, 0x0A, 0x0A, 0x0A, 0x0E, 0x00, 0x08, 0x0F, 0x00,//"高",49
	
}

  Simple GUI 使用字体资源时 需要定制一个接口结构体
在这里插入图片描述
在这里插入图片描述
因为我们的字模资源是定制的,所以索引函数需要自己编写。上述资源,对每一个文字进行重新编号,也就是编码,同时根据前文保持步进一致以方便数据寻址的原则,汉字等全角字符全部间隔一个编号,例如上述字符“0”编号为0x00,字符“:”编号为0x0A,字符“一”编号为0x800B,而字符七则编号为“0x800D”,中间跳过一个编码0x800C,此处为了区别半角与全角字符,所有非ASCII字符全部以0x80开头,占两字节。 所以定义索引函数如下

SGUI_INT GetCharIndex_CUSTOM(SGUI_UINT32 uiCode)
{
    /*----------------------------------*/
	/* Variable Declaration				*/
	/*----------------------------------*/
	SGUI_INT					iIndex;
	SGUI_UINT8					uiLowByte;

	/*----------------------------------*/
	/* Initialize						*/
	/*----------------------------------*/
	// Initialize variable.
	iIndex =				    SGUI_INVALID_INDEX;

	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	/* for ASCII characters. */
	if(uiCode < 0x11)//定制的字模中 索引号0~10为ASCII码,为半字
	{
		iIndex = uiCode;
	}
	else
	{
		uiLowByte = (SGUI_UINT8)(uiCode&0xFF);
		/* For symbol characters. */
		if(uiCode > 0x80)
		{
			iIndex =uiLowByte;//因为非ASCII字符全部以0x80开头,占两字节,
							  //所以取低位作为索引
		}
	}
	return iIndex;
}

其他三个函数接口如下

/*************************************************************************/
/** Function Name:	StepNext_CUSTOM									    **/
/** Purpose: 通过输入指针读取当前字符代码的顺序,然后步进到下一个字符开始指   **/
/** Resources:		None.												**/
/** Params:																**/
/**	@ cszSrc[in]:当前字符指针											**/
/**	@ puiCode[in]:	Character code.										**/
/** Return:			Next character start pointer.   					**/
/*************************************************************************/
SGUI_CSZSTR StepNext_CUSTOM(SGUI_CSZSTR cszSrc, SGUI_UINT32* puiCode)
{
    /*----------------------------------*/
	/* Variable Declaration				*/
	/*----------------------------------*/
	const SGUI_CHAR*            pcNextChar;
	SGUI_UINT32					uiCode;

	/*----------------------------------*/
	/* Initialize						*/
	/*----------------------------------*/
	pcNextChar =                cszSrc;
	uiCode =					0;

	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	if(NULL != pcNextChar)
    {
    	do
		{
			uiCode = (SGUI_BYTE)(*pcNextChar++);
			if(uiCode < 0x11)
			{
				break;
			}
			uiCode = uiCode<<8;
			uiCode |= (SGUI_BYTE)(*pcNextChar++);
		}while(0);
    }
	*puiCode = uiCode;

    return pcNextChar;
}

/*************************************************************************/
/** Function Name:	CUSTOM_GetFontData								    **/
/** Purpose:		从字体数据中读取字符数据				         		**/
/** Resources:		None.												**/
/** Params:																**/
/**	@ sStartAddr[in]: .	          读取内存中的开始地址			**/
/**	@ pDataBuffer[in]: .		字符数据转出储缓冲区指针				**/
/**	@ sReadSize[in]: Size of data will be read, always mean the buffer  **/
/**                 size.将读取的数据大小,始终表示缓冲区大小                               				**/
/** Return:			Data in process was be read.        				**/
/*************************************************************************/
SGUI_SIZE CUSTOM_GetFontData(SGUI_SIZE sStartAddr, SGUI_BYTE* pDataBuffer, SGUI_SIZE sReadSize)
{
	/*----------------------------------*/
	/* Variable Declaration				*/
	/*----------------------------------*/
	SGUI_SIZE					sReadCount;
	const SGUI_BYTE*			pSrc = DEMO_H12+sStartAddr;
	SGUI_BYTE*					pDest = pDataBuffer;

	/*----------------------------------*/
	/* Initialize						*/
	/*----------------------------------*/
	pSrc =						DEMO_H12+sStartAddr;//DEMO_H12为定制字模数组
	pDest =						pDataBuffer;

	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	if(NULL != pDataBuffer)
	{
		for(sReadCount=0; sReadCount<sReadSize; sReadCount++)
		{
			*pDest++ = *pSrc++;
		}
	}
	return sReadCount;
}

/*************************************************************************/
/** Function Name:	CUSTOM_GetFontData								    **/
/** Purpose:		根据字码判断当前文字是全角或是半角文字。.         		**/
/** Resources:		None.												**/
/** Params:																**/
/**	@ sStartAddr[in]: .						**/
/**	@ pDataBuffer[in]: .				**/
/**	@ sReadSize[in]: .                               				**/
/** Return:			Data in process was be read.        				**/
/*************************************************************************/
SGUI_BOOL CUSTOM_IsFullWidth(SGUI_UINT32 uiCode)
{
    /*----------------------------------*/
	/* Variable Declaration				*/
	/*----------------------------------*/
	SGUI_BOOL					bReturn;

	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
    if(uiCode < 0x11)
	{
		bReturn = SGUI_FALSE;//半角
	}
	else
	{
		bReturn = SGUI_TRUE;//全角
	}

	return bReturn;
}

定义好字体资源函数后 再定义一个字体资源结构体将定制字库进行封装

const SGUI_FONT_RES CUSTOM_FZXS12 =
{
    /*SGUI_INT   iHalfWidth*/            6,
    //本文章的定制字模为12X12的字体 所以半字宽度为6
    /*SGUI_INT    iFullWidth*/            12,
    /*SGUI_INT    iHeight*/               12,
    //字模大小数据
    
	/*SGUI_FN_IF_GET_CHAR_INDEX     fnGetIndex*/            GetCharIndex_CUSTOM,
	/*SGUI_FN_IF_GET_DATA           fnGetData*/             CUSTOM_GetFontData,
	/*SGUI_FN_IF_STEP_NEXT          fnStepNext*/            StepNext_CUSTOM,
	/*SGUI_FN_IF_IS_FULL_WIDTH      fnIsFullWidth*/         CUSTOM_IsFullWidth,
	//字模接口函数
};

定制字库资源的使用

 这是本文章最想讲解的地方,因为我一开始不理解重编码的应用所以研究了好久。

先来看文本接口显示ASCII码的操作

		//在屏幕上显示"Hello "字体
		stDisplayArea.iPosX=40;
		stDisplayArea.iPosY=48;
		stDisplayArea.iHeight=16;
		stDisplayArea.iWidth=73;
		stInnerPos.iPosX=0;
		stInnerPos.iPosY=0;
    SGUI_Text_DrawText(pstDeviceIF,"Hello",&CUSTOM_FZXS12, &stDisplayArea, &stInnerPos, SGUI_DRAW_NORMAL);

在看看显示定制字库中的汉字的操作

		//在屏幕上显示”立春“字体
		stDisplayArea.iPosX=40;
		stDisplayArea.iPosY=48;
		stDisplayArea.iHeight=16;
		stDisplayArea.iWidth=73;
		stInnerPos.iPosX=0;
		stInnerPos.iPosY=0;
    SGUI_Text_DrawText(pstDeviceIF,"\x80\x4F\x80\x3B",&CUSTOM_FZXS12, &stDisplayArea, &stInnerPos, SGUI_DRAW_NORMAL);

这里的"\x80\x4F\x80\x3B"是我们对“立春”字模数据的重编码,拿出“立”字"\x80\x4F"进行分析 \x08是我们规定非ASNII码字符高位为0x80,而\x4F是我们把字模排序后 对应的索引号 。这个编码经过字体文本组件内的字体资源函数接口处理后会正确取出对应的字模数据,并显示在屏幕上。
前文提到作者开发的那款提重和重编码的软件,在这里简单介绍一下用法
Ait
列出需要的字符
在这里插入图片描述
点击图标去重并生成重编码
在这里插入图片描述
在这里插入图片描述
这里的重编码和源文本是对应的,可直接复制粘贴到代码中

为了方便修改和维护 可以把要显示的字符数据定义成一个宏

#define SCR1_LIST_HINT					("\x80\x4F\x80\x3B")//立春
		//在屏幕上显示”立春“字体
		stDisplayArea.iPosX=40;
		stDisplayArea.iPosY=48;
		stDisplayArea.iHeight=16;
		stDisplayArea.iWidth=73;
		stInnerPos.iPosX=0;
		stInnerPos.iPosY=0;
    SGUI_Text_DrawText(pstDeviceIF,SCR1_LIST_HINT,&CUSTOM_FZXS12, &stDisplayArea, &stInnerPos, SGUI_DRAW_NORMAL);

至此本文章结束。

  • 10
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值