点阵字模的显示

    你是否碰到过用启动盘启动系统后用DIR命令得到一串串莫名其妙的字符?有经验的朋友会告诉你:那是汉字。汉字?你不禁会问:怎么一个我一个也不认识。但那确确实实是汉字,如果你启动UCDOS或其他的汉字系统后,就会看到那是一个个熟悉的汉字。同样是汉字,为什么前后会看到不同的结果?呵呵,其实在电脑硬件中,根本没有汉字这个概念,也没有英文的概念,这铁玩意认识的概念只有——内码。  
   
  汉字的内码  
   
    点头表示什么?是“对”、“YES”,偏偏有的地方表示的意义却恰恰相反。一个动作,有不同的诠释;一个问题,有不同的答案;而一个符号,却有不同的意义,关键在于:你是如何地理解。在电脑中亦如此,所有的数据都是以0和1保存的,按不同的数据操作,可以得到不同的结果。对于显示英文操作,由于英文字母种类很少,只需要8位(一字节)即可。而对于中文,常用却有5000以上,于是我们的DOS前辈想了一个办法,就是将ASCII表的高128个很少用到的数值以两个为一组来表示汉字,即汉字的内码。而剩下的低128位则留给英文字符使用,即英文的内码。不信,你可以用记事本写一C文件:  
   
  main()  
  {  
          unsigned   char   *s,*e="ABcd",*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();  
  }  
   
  再用TC输入*.txt打开运行,看见了没有,那些数值即英文和汉字的各字节内码。  
   
  汉字字模  
   
    得到了汉字的内码后,还仅是一组数字,那又如何在屏幕上去显示呢?这就涉及到文字的字模,字模虽然也是一组数字,但它的意义却与数字的意义有了根本的变化,它是用数字的各位信息来记载英文或汉字的形状  
   
   
    在硬件系统内,英文的字模信息一般固化在ROM里,即使在没有进入系统的CMOS里,也可以让你看到英文字符。而在DOS下,中文的字模信息一般记录在汉字库文件HZK16里。  
   
  汉字库文件  
   
    了解字母和汉字是按字模位信息显示的原理后,那如何得到汉字的字模信息呢?难道要我们自己去做?NO。DOS前辈们经过艰辛的努力,将制作好的字模放到了一个个标准的库中以免去后辈的麻烦,这就是点阵字库文件。一般我们使用16*16的点阵宋体字库,所谓16*16,是每一个汉字在纵、横各16点的区域内显示的。不过后来又有了HZK12、HZK24,HZK32和HZK48字库及黑体、楷体和隶书字库。虽然汉字库种类繁多,但都是按照区位的顺序排列的。前一个字节为该汉字的区号,后一个字节为该字的位号。每一个区记录94个汉字,位号则为该字在该区中的位置。因此,汉字在汉字库中的具体位置计算公式为:94*(区号-1)+位号-1。减1是因为数组是以0为开始而区号位号是以1为开始的。这仅为以汉字为单位该汉字在汉字库中的位置,那么,如何得到以字节为单位得到该汉字在汉字库中的位置呢?只需乘上一个汉字字模占用的字节数即可,即:(94*(区号-1)+位号-1)*一个汉字字模占用字节数,而按每种汉字库的汉字大小不同又会得到不同的结果。以16*16点阵字库为例,计算公式则为:(94*(区号-1)+(位号-1))*32。汉字库文该从该位置起的32字节信息即记录了该字的字模信息。  
   
   
  汉字库文件  
   
    了解点阵汉字及汉字库的构成原理后,显示汉字就变得简单。以16*16点阵字库为例,通常的方法是:将文件工作指针移到需要的汉字字模处、将汉字库文件读入一2*16数组再用for循环一位位地显示。以使用VGAHI模式显示“我”字为例,程序如下:  
  #include   "graphics.h"  
  #include   "stdio.h"  
  main()  
  {  
          int   i=VGA,j=VGAHI,k;  
          unsigned   char   mat[16][2],chinease[3]="我";  
          FILE   *HZK;  
          if((HZK=fopen("hzk16","rb"))==NULL)  
                  exit(0);  
          initgraph(&i,&j,"");  
          i=chinease[0]-0xa0;j=chinease[1]-0xa0; /*获得区码与位码*/  
          fseek(HZK,(94*(i-1)+(j-1))*32l,SEEK_SET);  
          fread(mat,32,1,HZK);  
   
          for(j=0;j<16;j++)  
                  for(i=0;i<2;i++)  
                          for(k=0;k<8;k++)  
                                  if(mat[j]&(0x80>>k)) /*测试为1的位则显示*/  
                                          putpixel(i*8+k,j,WHITE);  
   
          getch();  
          closegraph();  
          fclose(HZK);  
  }  
  怎么样?只要掌握了正确的方法,显示汉字并不复杂。  
   
  打印字库文件和HZK12  
   
    如果你有UCDOS的HZK24S(宋体)、HZK24K(楷体)或HZK24H(黑体),你还可以使用不同字体的大字模汉字了。HZK24系列是24*24的点阵字库,每字模占用3*24字节。如果你按照HZK16的显示方法的话,你会看到......呵呵,字被放倒了。这是因为该类字库与一般的汉字库不同,这类大字模汉字库是专供打印的打印字库,为了打印的方便将字模都放倒了,你使用时,只要将字模的位信息纵横转置显示即可。例如你如果定义为mat[24][3]则应该这样输出:  
          for(i=0;i<24;i++)  
                  for(j=0;j<24;j++)  
                          if((0x80>>i%8)&mat[j][i/8]) /*转置显示*/  
                                  putpixel(j+x,y+i,color);  
    还有一类字库HZK12,虽然属于标准字库类型,但如果你将它的字模当作12*12位计算的话,根本无法正常显示汉字。因为字库设计者为了使用的方便,字摸每行的位数均补齐为8的整数倍,于是实际该字库的位长度是16*12,虽然每行都多出了4位,但这4位都是0(不显示),并不影响显示效果。

 

 

以上内容转载自:http://www.civilnet.cn/bbs/browse.php?topicno=648


补充:

以UCDOS的HZK16宋体字库为例,32个字节,每个字节,为8位(bit),每位代表一个像素,每行2个字节16位,共16行,所以称之为16*16点阵字库。

以下为中文“三”的字模信息:
2进制                          16进制
00000000 00000000 0x00 0x00
00000000 00001000 0x00 0x08
01111111 11111100 0x7f 0xfc
00000000 00000000 0x00 0x00
00000000 00000000 0x00 0x00
00000000 00000000 0x00 0x00
00000000 00010000 0x00 0x10
00111111 11111000 0x3f 0xf8
00000000 00000000 0x00 0x00
00000000 00000000 0x00 0x00
00000000 00000000 0x00 0x00
00000000 00000000 0x00 0x00
00000000 00000100 0x00 0x04
11111111 11111110 0xff 0xfe
00000000 00000000 0x00 0x00
00000000 00000000 0x00 0x00

可以这样理解:区位号代表某个字在字库文件中的起始位置,从起始位置开始的32个字节[以16*16字库为例]代表字体的形状。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值