完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980
第52章 STM32H7的LTDC应用之点阵字体和字符编码(重要)
本章节主要为大家讲解ASCII字符集,ASCII扩展字符集,GB2312字符集,GBK字符集和Unicode字符集。其中,字符编码这块涉及到的知识点非常多,特别是Unicode字符集的编码,涉及到的知识点极其多。大家如果有精力的话,最好可以花点时间把Unicode的发展史捋清楚了。本章节笔者能够做的是把相关的知识点告诉大家,让大家有一个全面的认识。
52.1 初学者重要提示
52.2 编码基础知识
52.3 汉字点阵原理
52.4 总结
52.1 初学者重要提示
- 本章节讲解的GB2312和GBK比较容易理解,而Unicode是全球统一码,所以涉及到的知识点比较多,也复杂些。
- 当前Windows系统字符管理已经全部采用Unicode字符集,编码形式是UTF-16 LE (LE表示小端格式)编码。比如我们通过记事本保存的时候选择编码类型Unicode,其实就是选择的UTF-16 LE。而我们平时所说的中文版Windows系统是指用户在选择不支持Unicode的程序中显示文本时所使用的语言。
- 区分清楚什么是字符,字符集。字符(Character)是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。字符集(Character set)是多个字符的集合,字符集种类较多,每个字符集包含的字符个数不同,常见字符集名称:ASCII字符集、GB2312字符集、BIG5字符集、 GB18030字符集、Unicode字符集等。而UTF-16,UTF-8仅仅是Unicode字符集的编码形式,他们不是字符集,不要混淆了。
52.2 编码基础知识
关于字符编码的知识,我们这里换一种讲解方式,从字符编码的发展史来讲解,做到知其然知其所以然。
52.2.1 ASCII字符集及其编码
ASCII字符随着计算机的发明而诞生,计算机最早是在美国开始使用,当时为了将生活中用到的各种文字和符号能够通过计算机进行存储、显示和传输,人们就将控制字符、空格、标点符号、数字和大小写字母进行编号,从编号0到编号127,共128个字符。到了1967年,专门为这个方案起了一个名字叫ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)。
下面是128个ASCII字符:
随着计算机的发展,世界各地都开始使用计算机,但是很多国家用的不是英文,他们的字母里有很多是ASCII字符集中没有的。为了可以在计算机中保存这些非英文国家的文字和符号,决定采用127号之后未编排的空位来表示这些新的字母和符号,并且还加入了很多画表格时需要用到的横线、竖线、以及交叉线等形状,一直把序号编到了最后一个状态255,从128到255的字符被称为扩展字符集。具体字符就不整理出来了,电脑端不太好打印出,大家可以看此网站http://www.ascii-code.com/ 。
52.2.2 GB2312字符集及其编码
等计算机传到中国来,一个字节(一个字节是8位,共可以表达2^8 = 256个字符)的所有编码已经用完,没有可以使用的编码来表示汉字了,而且一个字节不能表示6000多个常用的汉字,所以汉字就需要2个字节来表示。
第一个字节从编号0到编号127的字符不变,还是表示ASCII,而之后的0xA1到0xFE用于汉字编码,这个字节被称为汉字的区号或者高位字节,0xA1到0xFE换算成区号就是从01区到94区(换算关系就是对编码值减去0xA0)。
第二个字节的0xA1到0xFE用于汉字编码,这个字节被称为汉字的位号或者低位字节,0xA1到0xFE换算成位号就是从位号01到位号94(换算关系就是对编码值减去0xA0)。根据区号和位号的设置,那么就有94*94 = 8836个编码可供使用。在这些编码里,我们还把数学符号、罗马希腊字母、日文的假名都编码进去了,连在 ASCII里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,即全角字符,而原来在127号之前的那些字符称为半角字符。
由这些编码组成的字符,我们为其取了一个名字叫GB2312。GB2312是对ASCII字符集的简体中文扩展,这个就是GB2312的由来。GB2312编码全称《信息交换用汉字编码字符集——基本集》,由中国国家标准总局1980年发布,1981年5月1日开始实施的一套国家标准,标准号是GB 2312—1980。
GB2312编码适用于汉字处理、汉字通信等系统之间的信息交换,通行于中国大陆,新加坡等地也采用此编码。中国大陆几乎所有的中文系统和国际化的软件都支持GB2312。基本集共收入汉字6763个以及非汉字图形字符682个。整个字符集分成94个区,每区有94个位。每个区位上只有一个字符,因此可用所在的区和位来对汉字进行编码,称为区位码。其中,这94个区的分配如下:
- 01-09区为特殊全角符号共682个。
- 16-55区为一级汉字共3755个,按音序排。
- 56-87区为二级汉字共3008个,按部首/笔画排序。
- 10-15区和88-94区共13个区暂未编码。
区位码和汉字编码:
为了编码兼容ASCII码且机内存储不与ASCII码冲突,GB2312并不直接使用0x0101-0x5E5E(区位码)对字符进行表示和存储,而是使用实际的编码范围0XA1A1到0XFEFE。例如“啊”字在大多数程序中,会以两个字节0xB0A1储存。而区位码就是0x1001,他们之间的关系就是高位字节和低位字节都差0xA0。0xB0 - 0x10 = 0xA0,0xA1 - 0x01 = 0xA0。
ASCII区,GB2312编码的全角字符区和汉字区的所有字符可以看下这个帖子:
http://bbs.armfly.com/read.php?tid=201 ,初学者务必看下,非常有必要。
特别补充:上面讲解的内容中隐藏了一个小知识,但是在我们做中英文混合显示时很有用,只要高字节超过127(0x80)就认为是双字节编码,即GB2312,而不用管低字节是否低于127(0x80)。
52.2.3 GBK字符集及其编码
随着计算机使用范围的扩大,发现很多的人名在GB2312编码中找不到,还有很多文字和符号将来可能还会用到,我国在1995年12月完成GBK规范,全称汉字内码扩展规范,共收入 21886 个汉字和图形符号,其中汉字(包括部首和构件)21003 个,图形符号 883 个。
GBK编码也需要两个字节来表示,第一个字节是区号,范围是81到FE,第二个字节是位号,位号是该字在该区中的位置,范围是40到7E和80到FE,其中7F部分是没有编码的,这点要特别注意。下面是GBK的编码范围表。
从上面表格可以看出,GBK区间是8140~FEFE,其中XX7F部分是要删除的, GBK 里有FE-81+1=126个区 ,每个区有FE-40-1+1=190个字符,因此一共有126*190=23940个字符,与上面的表格编码数是一致的。
特别补充,GBK编码与 Unicode 字符集中的UCS-2编码完全兼容,这一点很重要,后面emWin的学习中要用到。
52.2.4 Unicode字符集及其编码
由于各个国家都像中国这样搞出一套自己的编码标准,结果互相之间谁也不懂谁的编码,谁也不支持别人的编码。基于此,国际组织决定着手解决这个问题,即重新弄一套包括了地球上所有文化、所有字母和符号的编码。他们打算叫它”Universal Coded Character Set“,简称 UCS, 俗称Unicode。Unicode有两种编码UCS-2和UCS-4。UCS-2用两个字节编码,UCS-4用4个字节编码。
Unicode伴随着通用字符集的标准而发展,同时也以书本的形式对外发表。Unicode至今仍在不断增修,每个新版本都加入更多新的字符。目前最新的版本为2016年6月21日公布的9.0.0版本,已经收入超过十万个字符(第十万个字符在2005年获采纳)。Unicode涵盖的数据除了视觉上的字形、编码方法、标准的字符编码外,还包含了字符特性,如大小写字母。
关于Unicode这块,我们这里补充点知识,来自wiki百科中文版,非常值得一读,笔者这里将其整理到教程里面来了:
=========================================================
大概来说,Unicode编码系统可分为编码方式和实现方式两个层次。
- 编码方式
统一码的编码方式与ISO 10646的通用字符集概念相对应。目前实际应用的统一码版本对应于UCS-2,使用16位的编码空间,也就是每个字符占用2个字节。这样理论上一共最多可以表示2^16,即65536个字符,基本能满足各种语言的使用。实际上当前版本的统一码并未完全使用这16位编码,而是保留了大量空间以作为特殊使用或将来扩展。
上述16位统一码字符构成基本多文种平面。最新(但未实际广泛使用)的统一码版本定义了16个辅助平面,两者合起来至少需要占据21位的编码空间,比3字节略少。但事实上辅助平面字符仍然占用4字节编码空间,与UCS-4保持一致。未来版本会扩充到ISO 10646-1实现级别3,即涵盖UCS-4的所有字符。UCS-4是一个更大的尚未填充完全的31位字符集,加上恒为0的首位,共需占据32位,即4字节。理论上最多能表示2^31个字符,完全可以涵盖一切语言所用的符号。
基本多文种平面的字符的编码为U+hhhh,其中每个h代表一个十六进制数字,与UCS-2编码完全相同。而其对应的4字节UCS-4编码后两个字节一致,前两个字节的所有位均为0。
- 实现方式
Unicode的实现方式不同于编码方式。一个字符的Unicode编码是确定的。但是在实际传输过程中,由于不同系统平台的设计不一定一致,以及出于节省空间的目的,对Unicode编码的实现方式有所不同。Unicode的实现方式称为Unicode转换格式(Unicode Transformation Format,简称为UTF)。
例如,一个仅包含基本7位ASCII字符的Unicode文件,如果每个字符都使用2字节的原Unicode编码传输,其第一字节的8位始终为0。这就造成了比较大的浪费。对于这种情况,可以使用UTF-8编码,这是一种变长编码,它将基本7位ASCII字符仍用7位编码表示,占用一个字节(首位补0)。而遇到与其他Unicode字符混合的情况,将按一定算法转换,每个字符使用1-3个字节编码,并利用首位为0或1进行识别。这样对以7位ASCII字符为主的西文文档就大幅节省了编码长度。类似的,对未来会出现的需要4个字节的辅助平面字符和其他UCS-4扩充字符,2字节编码的UTF-16也需要通过一定的算法进行转换。
再如,直接使用与Unicode编码一致(仅限于BMP字符)的UTF-16编码,由于每个字符占用了两个字节,在Mac OS系统和Windows系统上,对字节顺序的理解是不一致的。这时同一字节流可能会被解释为不同内容,如某字符为十六进制编码4E59,按两个字节拆分为4E和59,在Mac上读取时是从低字节开始,那么在Mac OS会认为此4E59编码为594E,找到的字符为“奎”,而在Windows上从高字节开始读取,则编码为U+4E59的字符为“乙”。就是说在Windows下以UTF-16编码保存一个字符“乙”,在Mac OS环境下打开会显示成“奎”。此类情况说明UTF-16的编码顺序若不加以人为定义就可能发生混淆,于是在UTF-16编码实现方式中使用了大端序(Big-Endian,简写为UTF-16 BE)、小端序(Little-Endian,简写为UTF-16 LE)的概念,以及可附加的字节顺序记号解决方案,目前在PC机上的Windows系统和Linux系统对于UTF-16编码默认使用UTF-16 LE。
此外Unicode的实现方式还包括UTF-7、Punycode、CESU-8、SCSU、UTF-32、GB18030等,这些实现方式有些仅在一定的国家和地区使用,有些则属于未来的规划方式。目前通用的实现方式是UTF-16小端序(LE)、UTF-16大端序(BE)和UTF-8。在微软公司Windows XP附带的记事本(Notepad)中,“另存为”对话框可以选择的四种编码方式除去非Unicode编码的ANSI(对于英文系统即ASCII编码,中文系统则为GB2312或Big5编码)外,其余三种为“Unicode”(对应UTF-16 LE)、“Unicode big endian”(对应UTF-16 BE)和“UTF-8”。
目前辅助平面的工作主要集中在第二和第三平面的中日韩统一表意文字中,因此包括GBK、GB18030、Big5等简体中文、繁体中文、日文、韩文以及越南喃字的各种编码与Unicode的协调性被重点关注。考虑到Unicode最终要涵盖所有的字符,从某种意义而言,这些编码方式也可视作Unicode出现之前的实现方式,如同ASCII及其扩展Latin-1一样,后两者的字符在16位Unicode编码空间中的编码第一字节各位全为0,第二字节编码与原编码完全一致。但上述东亚语言编码与Unicode编码的对应关系要复杂得多。
=========================================================
更多Unicode相关知识,大家可以学习如下四个地址:
官网:http://www.unicode.org/
百度百科:超链接地址
wiki百科中文版:https://zh.wikipedia.org/wiki/Unicode
wiki百科英文版(更详细些):https://en.wikipedia.org/wiki/Unicode
更多UTF-8编码相关知识,大家可以学习如下三个地址:
百度百科:超链接地址
wiki百科中文版:https://zh.wikipedia.org/wiki/UTF-8
wiki百科英文版(更详细些): https://en.wikipedia.org/wiki/UTF-8
52.3 汉字点阵原理
简单的理解,一个字的点阵是指这个汉字用多少个像素点来描述。下面举一个16 点阵汉字库(宽度 x 高度 = 16x16)给大家说明一下:
16点阵每个字型的点阵数据为 16×16(横行点数×纵列点数),共 256 个二进制位,32 个字节。 汉字 16 点阵字型数据的 32 个字节排列次序是以 0 字节开始到 31 字节结束,均用十六进制表示,其记录格式如下:
以一个点阵汉字“啊”为例给大家说明下:
“啊”是汉字区第 1 个汉字,对应的数据为:
0x00,0x00,0x0E,0xFC,0xEA,0x08,0xAA,0x08,
0xAA,0xE8,0xAA,0xA8,0xAC,0xA8,0xAA,0xA8,
0xAA,0xA8,0xAA,0xA8,0xEA,0xE8,0xAA,0xA8,
0x0C,0x08,0x08,0x08,0x08,0x28,0x08,0x10
大家明白了点阵字库的排列原理,编程实现汉字显示就比较容易了,后面章节的汉字显示要用到。
52.4 总结
本章节主要把大家后面章节要用到的知识点进行了说明,其实字符编码这块涉及到的知识点还是非常多的,如果想完全弄明白还要花一番心思和时间去查阅相关资料。
原文地址:https://www.cnblogs.com/armfly/p/12307280.html