字模提取详细解读
offset = (94*(qh-1)+(wh-1))*32L;/*计算该汉字在字库中偏移量*/ fseek(HZK,offset,SEEK_SET); fread(buff,32,1,HZK); /*将文件指针移动到偏移量的位置*/ /*从偏移量的位置读取32个字节*/
printf("qh:%d,wh:%d,offset:%ld\n\r",qh,wh,offset); }
前不久,在网上看到一个生成点阵字的网站。觉得很有意思! 到底什么是点阵字,点阵字和字模之间有什么关系?
让我们先看一个点阵汉字和一个英文字母:
** ************************** ** ** ** ** ** **
************************** ** ** ** ** ** ** **
一个专门的文件中,这个文件在 UCDOS 和 CCDOS 中都有, 文件名是 HZK16。 也就是16x16点阵的汉字字模信息,所谓16x16,就是说这个汉字在横向有16 个点,和纵向16个点的区域里显示。还有 24x24,32x32等。 我们也可以在 UCDOS 下找到英文字模的信息文件,文件名是 ASC16,这里记 录了英文字符的字模信息。ASC16文件记录的英文字符是 8x16点阵的。这些记 录字符字模信息的文件通常也叫字库文件。
看一个 C 程序示例:
程序代码
main() { unsigned char *s,*e="A",*c="王"; clrscr(); printf("English char ="); s=e; while(*s!=0) /*C 的字符串以0为结束符*/ { printf("%3d,",*s); s++; } printf("\nChinease char="); s=c; while(*s!=0) { printf("%3d,",*s); s++; } getch(); }
ASC16文件的大小刚好为 4K (4,096 个字节),每一英文字符横向有8个点, 纵 向有16个点。也就是说要描述一个英文字符的点阵信息,必须要 16*8=128bit=16Byte。而英文字符是一个字节表示,所能表示的最字符数为 2 的8次方,也就是256个字符(ASCII 中是从0到 255)。256个字符*16(每个字符 要16个字节) = 4096 字节。 刚好为 ASC16文件的大小。因此,我们要读取
***********************************/ void getHzKCode(char *c,char buff[]) { unsigned char qh,wh; unsigned long offset; FILE *HZK;
/*打开字库文件 hzk16*/ if((HZK=fopen("hzk16",#39;t open haz16,Please add it?"); getch(); exit(0); } /*区码=内码(高字节)-160 位码=内码(低字节)-160*/ qh wh = *(c) -0xa0; = *(c+1) -0xa0; /*10进制的160等于16进制的 A0*/ /*获得区码与位码*/
#include "stdio.h"
/********************************** * 得到英文字符的字模信息,存入数组 * 参数:
* *
*c:要得到字模信息的字符指针 buffer[]:存储得到字模信息的数组
* 无返回值 ***********************************/ void getAscCode(char *c,char buff[]) { unsigned long offset; FILE *ASC;
******************************
........ ...#.... ..###... .##.##..
##...##. ##...##. #######. ##...##. ##...##. ##...##. ##...##. ........ ........ ........ ........ ........
printf("ASCII:%d,offset:%d \n\r",*c,offset); }
/********************************** * 得到汉字字符的字模信息,存入数组 * 参数: * * *c:要得到字模信息的字符指针 buffer[]:存储字模信息的数组
* 无返回值
/********************************** * 根据字模信息输汉字字符 * 参数: * * * *mat:字模指针 *c1 :字模中为1的点显示的字符,也就是前景字符 *c2 :字模中为0的点显示的字符,也就是背景字符
让我们先来认识一下区位码: 1981年 5月,我国国家标准总局颁布了《信息交换用汉字编码字符集》 (GB2312-80) ,简称国家标准汉字编码,也叫国标码。国标码共收进标准字 符7445个。其中一级汉字3755个,二级汉字3008个,共计6763个汉字。 由 于汉字的字符多,一个字节(即8位二进制代码)不足以表示所有的常用汉字。 汉字国标码的每个汉字或符号在计算机中都使用2个字节( 16位二进制)代码 来表示。
现在我们知道,可以从区位码得到汉字,也可以从汉字反查出区位码。那么我 们如何从内码得到区位吗? 汉字内码与区位码之间有一个简单的数学关系:
内码高字节 = 区码+A0H = 区码 +160 内码低字节 = 位码+A0H = 位码+160
这个转换关系,我也不清楚原因,有谁知道还望指点。网上的大师们说这样转 换,咱们就这样转换吧。
汉字字模: 现在让我们来认识一下什么是字模, 所谓字模就是是汉字 (或者字符) 的形态。 字模中保存了汉字的点阵信息,记录组成一个字符的点在何处显示,在何处不 显示。我们只要得到汉字的字模,我们就可以很容易的程序来控制,把这个字 符画出来。 我们刚刚得到的仅仅是汉字的内码, 并根据汉字内码得到区位码,由区位码查 表得到汉字。那么我们如何来得到汉字的字模了? 用过 UCDOS( 或者 CCDOS , 估计现在只有少数人还知道 UCDOS 是什么东东) 的人应该知道,通过 UCDOS 可以让 DOS 系统下正确的显示中文目录。不通 过 UCDOS 之类的软件,在纯 DOS 下,我们看到的中文目录会是一堆的乱码, 而英文目录能够正确显示,这是什么原因了。 这是因为,英文的字模信息是一般固化在 ROM 里。中文字模信息一般记录在
英文字模的信息,我们就先得到这个字符的 ASCII 码。 以得到字符"A"的字模信息为例: 假如我们要得到的字母 A 的字模信息,我们得到"A"的 ASCII 值为 65,我们就 可以算出字符"A"的字模信息在 ASC16文件中的偏移量=(65*16)+1=1041字 节(注意这个数字,我们将在后面用程序进行验证),我们只需要从 ASC16文件 中1041字节开始读取16个字节就可以得到 "A"的字模信息了。
而每一个汉字占32个字节,因此我们得到“王”字在字库文件(HZK16) 中的偏移 量为: 4220*32=135040字节 (注意这个数字, 我们在后面将用程序进行验证 )。 我们只需要从 HZK16文件中135040字节开始读取32个字节就可以得到“王 ”字 的字模信息了。
完整的原程序代码如下:
在 GB2312-80代码表中,纵向分为0~93,共 94行。将行号称为区号,列号称 为位号,分别有94个区和94个位。区号和位号用十进制表示,不足两位前面 补0。这样每个汉字或符号都可用 4位十进制表示。这就是我们常说的区位码。 每一区共有94个汉字,而位记录该汉字在该区中的具体位置。(记得我们以前 读书的时候,报考计算机考试,填写姓名都要我们用区位码填,我们都拿着自 己的姓名一个个去查, 我们查的那个东东就是区位码。 现在想想, 真是心寒呀。 还好,我后来就没有查了,弄了个 excel 的宏。把班上人的姓名全部放到一个 excel 中,然后一点鼠标,哈哈 …… 区位码全自动出来了)。
/*打开字库文件 asc16*/ if((ASC=fopen("asc16","rb"))==NULL){ printf("Can't open asc,Please add it?"); getch(); exit(0); } offset = *(c)*16+1; fseek(ASC,offset,SEEK_SET); fread(buff, 16, 1, ASC); /*通过 ascii 码算出偏移量*/ /*将文件指针移动到偏移量的位置*/ /*从偏移量的位置读取32个字节*/
同样,我们来看一下汉字字模。 汉字是16*16的所以描述一个汉字字模信息的大小为: 16*16=256bit=32Byte,汉字是按照区位码的顺序来排列的。 我们以得到”王“字的字模信息为例: 我们先得到”王“字的内码为:205,245,根据内码与区位码的转换关系得到 ” 王“字的区位码为:45,85。 由前面区位码介绍中, 我们知道, 每一区有94个汉字, 位号表示在该区的位置。 因此“王”字中区位码中的位置为: 94*(区号 -1) + (位号-1) = 94*((45-1)+(85-1)) = 4220。
我们刚刚输出“王 ”的内码为:205(高字节),245(低字节)。 由上面的换算关系, 可以得到“王”字的区位码为: 区码=205-160=45 位码=245-160=85
查一下区位码表,4585所表示的汉字正好是“王”。 也可以打开输入法,选择内码输入法,然后选择区位码,输入4585,就会输 出“王”字。