基于HZK16的汉字显示技术

国标汉字字符集(GB2312-80)在汉字操作系统中以汉字库的形式提供,并对汉字库的结构做了统一规定。汉字库的结构如图:

基于HZK16的汉字显示技术

HZK16的GB2312-80支持的汉字有6763个,符号682个。字库有94个区,其中一级汉字有3755个,按声序排列,二级汉字有3008个,按偏旁部首排列。每个区有94个位,每个位存一个汉字。这样每个汉字在汉字库中有确定的区号和位号。区号在前,位号在后,合成一个4位十进制数字,这就是区位码。区位码用两个字节存放(GB2312汉字是由两个字节编码的,范围为A1A1~FEFE。A1-A9为符号区,B0到F7为汉字区),第一个字节表示区号,第二个字节表示位号。只要知道了区位码,就可以知道该字在字库中的地址。

16×16点阵库中,每个点阵模用32个字节来描述,其中的每个点使用一个二进制位。当需要显示时,把某个汉字的16×16点阵信息直接送到显示器上,值为1的点在屏幕上显示一个亮点,值为0的点则不亮,这样就可以显示出相应的汉字。

在国标字库中,每个汉字还可以使用国标码。国标码与区位码之间的换算关系:

国标码的区号=区位码的区号+32(或20H)

国标码的位号=区位码的位号+32(或20H)

或 区码=区号-0xa0 (因为汉字编码是从0xa0区开始的,所以文件最前面就是从0xa0区开始,要算出相对区码)

位码=位号-0xa0

此外还有汉字内码。汉字内码是汉字信息处理系统内部表示汉字的编码,也称机内码。西文字符的机内码多采用一个字节来表示的ASCII码,有的系统则采用EBCDIC码。一般只使用7位来表示128个字符,而把高位用作奇偶校验(或者不用)。我国的国标GB2312-80规定,一个汉字用两个字节表示,目前规定每个字节也只用七位,其高位未作定义。为了保证系统的中西文兼容,意味着系统的机内码中必须保持ASCII(IBM-PC采用该码作为西文字符的机内码)的使用,同时又要允许汉字机内码的使用,并且使两者之间没有冲突。如果用GB2312-80中的国标码作为机内码,则在系统中同时存在ASCII码和国标码时,将会产生二义性。例如,机内有两个字节的内容分别为30H和21H,它们既可以表示汉字“啊”的国标码,又可以表示字符“0”和“!”的ASCII码。所以,原原本本地采用国标码作为汉字机内码是不行的,必须要加以适当的变换。
国标码规定,组成两字节代码的各字节的最高位均为0,但在机内码表示汉字时,应将每个字节的最高位置1,以表示该编码是汉字,这种编码称作为变形国标码。这样作既解决了西文机内码与汉字机内码的二义性,又保证汉字机内码与国标码之间有极简单的对应关系。

国标码两字节的最高位分别加1后,便得到机内码。“计”字机内码如图:

基于HZK16的汉字显示技术

这样国标码与机内码存在一种简单的对应关系:

机内码区号=国标码区号+128(或80H)

机内码位号=国标码位号+128(或80H)

因为知道了某汉字的内码,即可确定出对应的区位码,知道了区位码,就可以找出该汉字字模在字库中的存放地址,从该地址中调出对应汉字的32个字节的字模信息,就可以显示出16×16点阵组成的该汉字了。

从上文的分析可知,汉字内码与区位码存在固定的转换关系,设某汉字内码的十六进制数表示为0xkkjj,则相应区位码的区号qh和位号wh分别为:

qh=0xkk-0xa0;

wh=0xjj-oxa0;

若用十进制数表示内码为c1c2,则

qh=c1-160;

wh-c2-160;

即区位码qw=100*(c1-160)+(c2-160);相反要是知道了区位码qw,则也可以求得区号和位号:

qh=qw/100;

wh=qw-100*qh;

因而该汉字在汉字库中离起点的偏移位置(以字节为单位),可有表达式offset=(94*(qh-1)+(wh-1))*32L(32L为长整形数)计算,其中假设int qh,wh,qw,long offset。

对于16×16点阵汉字,其字模大小为(16×16)/8=32个字节,其输出时的排列方式如图:

基于HZK16的汉字显示技术

几种常用的汉字库中地址码offset的计算公式:

1、ucdos中的字库CCLIB.DAT存放16×16点阵字模:

offset=((qh-1)*94+(wh-1))*32L;

2、CCDOS 2.13中的字库HZK16存放16×16点阵字模:

offset=((qh-16)*94+wh-1+15*94)*32L;

3、SPDOS 5.0的简单字库CCLIB.DAT存放16×16点阵字模:

offset=((qh-7)*94+wh-1)*32L;

4、CCDOS 2.13中字库hzk24存放24×24点阵字模:

offset=((qh-16)*94+wh-1)*72;

下面以一个小示例显示汉字:

#include <stdio.h>

int main(void)
{
    char chs[32];
    FILE *fp;
    int i,j;
    unsigned long offset;
    unsigned char hz[]="计";
	unsigned char qh,wh;

	qh=hz[0]-0xa0;//获取区吗
	wh=hz[1]-0xa0;//获取位码
	
	/*
	//int a=hz[0];
	//int b=hz[1];
	//printf("%x%x",a,b);
	//hz[0] hz[1]分别为汉字的机内码
	//offset=((hz[0]-0xa1)*94+(hz[1]-0xa1))*32;//注意0xa1十进制数为161
	*/
    offset=((qh-1)*94+(wh-1))*32;//根据内码找出汉字在HZK16中的偏移位置
    if ((fp=fopen("HZK16","r"))==NULL) 
		return 1;
    fseek(fp,offset,SEEK_SET);
    fread(chs,32,1,fp);
    for (i=0;i<32;i++)
    {
        if (i%2==0) 
			printf("\n");   //每行两字节,16X16点阵
        for (j=7;j>=0;j--)
        {
            if (chs[i]&(0x01<<j))
				/*
                  chs[i] & 0x80 判断第7位 
                  chs[i] & 0x40 判断第6位 
                  chs[i] & 0x20 判断第5位 
                  chs[i] & 0x10 判断第4位 
                  chs[i] & 0x08 判断第3位 
                  chs[i] & 0x04 判断第2位 
                  chs[i] & 0x02 判断第1位 
                  chs[i] & 0x01 判断第0位
                  */
				printf("计"); //由高到低,为1则输出'字',反之输出' ';
            else
                printf("  ");
        }
    }
    fclose(fp);
    return 0;
}

得到的效果:基于HZK16的汉字显示技术

你可能感兴趣的:(zk)