在以前的博客中曾经讨论过,设计的Foxdisk代码段和数据段总共只能128K。可是随便哪个汉字库轻轻松松都超过了100K,大的有近500K(我设计的时候只用了24×24以及16×16的字模),无论如何是不能包含在程序中的。唯一的办法,是将需要用的汉字字模提取出来,实现小字库的汉字显示。
当然,如果改变Foxdisk的设计方法,比如采用很久以前用过的一种技术:在硬盘的末端存一个裁剪的DOS或者linux,用OS来支持。现在遇到的存储空间不够啊、想实现的功能难以实现啊,都能解决。并且还能复用大量的DOS/Linux的软件,还是很不错的。不过,这就失去了我当时设计的初衷了,本来就是用来学习底层知识的一个小项目,用这种方法则屏蔽了大量的实现细节,所以我就放弃了。不过,在公司早期的一款产品中(卖了好几年,技术支持巨难,后来被我停掉了)是用了这种方法的,有机会也开个博客仔细探讨下。
文字显示主要包括文字的读取和显示两个步骤。西方文字显示完全可以集成在一个ROM内,但是中文字太多,通常都要用到字库。中文字库有两大类型:点阵式字库和矢量字库。
点阵式字库是通过将中文字看成一个个点组成的二维阵列来实现显示;矢量字库则通过对文字每个笔划的起始点和结束点的记录来完成文字显示。很明显,点阵字如果要放大文字将会出现明显的不平滑现象;而矢量字无论字的大小都可以保证字体圆滑。但是由于点阵字理解简单、便于编程等原因,在很多领域点阵字库成为了主流。
当前只针对点阵字库进行讨论研究,并针对研究的各字体库进行分析,阐述其在编程上的一些区别。在此基础上,提供了无字库方案的实现过程及代码。 点阵字的显示原理其实很简单。在规定大小的区域格内,如16×16、24×24等,将需要显示的字的对应格填充即可。字库内对应的格则以1表示,没有填充的以0表示。如图所示:
这是英文字模的图样,而中文字模的图样是这样的:
图中的字模信息就存储在相应的字库中,而程序员就可以按照显示原理在显示器上以点位的方式显示字符。
每个英文字母都是由一个ASCII码组成的,而中文字是扩展ASCII码组成的。也就是说一个中文字是由左半边和右半边两部分的信息组成的。字库中的文字一般是按区位码的形式存放的,大体原理相同,但是在实际组织的时候有些细微的差别。[1]
本文所讨论的字库有HZK16(16×16汉字库)、HZK24S(24×24宋体)、HZK24H(24×24黑体)、HZK24F(24×24仿宋)、HZK24K(24×24楷体)、HZK24T(24×24汉字全角字符)。
对于24×24以上的汉字字库,比如48×48汉字字库,其存储方式与24×24 的相同,只是大小不同,简单修改就可适用,以下将作详细说明。
HZK16的中汉字存储可以用公式表示如下:
- 区码 = 文字左半边信息(扩展ASCII码) – 0xA0
- 位码 = 文字右半边信息 – 0xA0
- 在字库中的地址 = [(区码-1) *94 + (位码-1)] * 32
其中1、2步减去0xA0的原因是中文字符用到的扩展ASCII码是从0xA0之后开始计算的,94的来源是字库中每个区最多存放94个中文字点阵。另外,因为HZK16是16×16字体,每个字由32个字节组成(16位x16)。[1]
24×24字体库中文字库与 16×16字体库的组织有些不同。HZK24T中已经存放了汉字的全角字符,其余的各种字体的汉字库16区之前是独立在此的。也就是说,对HZK24S、HZK24H、HZK24F和HZK24K,公式如下:
- 区码 = 文字左半边信息(扩展ASCII码) – 0xA0
- 位码 = 文字右半边信息 – 0xA0
- 在字库中的地址 = [(区码-1- 15) *94 + (位码-1)] * 72
注意在第三步要减去15,前15区的字符存放在HZK24T中了。72表示24×24字库中汉字是按72字节存储的(24位x24)。
对于更大的字体,如32×32、48×48等,也是按照这样的方式存储。只是在第3步的计算中,32×32字体库中汉字占用 128字节,48×48字体库中汉字占用288字节。
汉字的点阵结构介绍完了,后面就面临着怎么提取字模以及显示的问题。实际上,在工具篇中已经有所涉及提取的问题了,下面两篇博客中详细描述。