汉字的编码与字模点阵小结 一、引言 在写的时候参考了以下两篇文章中的内容,在此向这两篇文章的作者表示敬佩和感谢.代码部分参考了http://www.ugia.cn/?p=82 作者legend文档部分参考了http://dev.gameres.com/Program/Control/fontDOS.htm 作者吴进二、汉字的内码、编码和点阵汉字显示的基本原理,计算机内一般都有汉字的字模库(也就是我们所说的点阵).在dos下显示汉字的基本过程是⑴计算机首先得到汉字的内码,这个就是存储在文本文件中的16进制数字,⑵由内码计算出汉字的区位码⑶由区位码得到字库文件中汉字点阵的真实位置⑷按点阵(坐标)信息在屏幕上的对应位置打点,就形成了我们看到的汉字字符1、内码内码就是汉字在计算机上存储时的编码,比如我们写一个文本文件,内容为"节日快乐",用16进制编辑器打开它,其内容为BD DA C8 D5 BF EC C0 D6这里的bd da就是第一个汉字"节"的内码.2、区位码区位码是国标gb2312中规定的汉字编码,这个是用来指导字库(点阵)文件的国家标准,不同的字库文件(比如12*12,16*16,24*24),其显示用来的点阵规模不共同,但是存储汉字的顺序都是一致的。这个会后面会举例说明。我们要知道的是,gb2312规定的区位码实际上就是一个94×94的矩阵。在此方阵中,每一行称为一个”区”,每一列称为一个”位”,因此,这个方阵实际上组成了一个有94个区(区号为十进制的1到94)、每个区内有94个位(位号分别为1到94)的汉字字符集。一个汉字所在的区号和位号简单地组合在一起就构成了该汉字的”区位码”。在汉字的区位码中,高两位为区号,低两位为位号。比如"节"的区位码为节 2958 其中 区码为29,也就是16进制的1D位码为58, 也就是16进制的3A所有汉字的区位码可以在下面的网址查到http://www.knowsky.com/resource/gb2312tbm.htm3、内码与区位码的转换内码高位=区码+A0(也就是10进制的160) 内码低位=位码+A0我们用"节"字来验证一下,内码低位为 DA = 区码3A+A0内码高位为 BD = 位码1D+A0注意在intel的机器上,内码的高位存储在低地址上,低位存储在高地址上. 4、点阵对计算机而言,每个汉字其实是一个点的方阵,标0的位置涂黑(背景色),标1的位置涂白(前景色),使这个方阵在屏幕看起来象一个汉字而已。比如"一"字,其12*12字库文件中的点阵信息为000000000000000000000000000000000000000000000000000000000100111111111110000000000000000000000000000000000000000000000000000000000000000000000000计算机在把汉字输出到显示设备上时,就按照点阵中的信息在屏幕的对应位置上涂色,标0的涂背景色(默认为黑色),标0的涂前景色(默认为白色)就形成了我们在屏幕上看到的汉字。5、字库文件前面说过,汉字的点阵信息是按照区位码的顺序存储在字库文件中的。所以要想取出某个汉字的点阵信息,就必须知道其在字库中的位置,这个位置的计算公式就是94*(区号-1)+位号-1减1是因为文件中的偏移量是以0为开始而区号位号是以1为开始的,需要换算一下。不过现在得到的是该汉字在汉字库中的位置,要得到在字模文件中的具体存储位置,还要乘上一个汉字字模占用的字节数。一个汉字字模站用的字节数就是其点阵占用的的字节数,比如对12*12字模,其占用的字节数就是12*12/8=16字节.综合起来,一个汉字点阵在字库文件中的存储位置计算公式为(94*(区号-1)+位号-1)*(单个字模的字节数)而 单个字模的字节数=点阵的行数*点阵的列数/一个字节所占的位数三、实现简单的字符灌水机 了解了以上的预备知识,我们就可以输出汉字点阵信息的程序了。代码如下#include "stdio.h"#include "string.h"#include "stdlib.h"const int reglen = 94; //每区(行)有 94 位(列)const int font_width = 12; // 单字点阵宽度(列数)const int font_height = 12; // 单字点阵高度(行数)const int dotsize = font_width * font_height /8; //一个汉字点阵所占的字节数const int subcode = 0xa0; //内码与区、位码的差值char *font_file_name = "simsun12.fon"; // 点阵字库文件名char str[] = "一"; //要显示点阵信息的汉字char bindot[dotsize] = {0}; //存储点阵信息的数组void printcharbindot(char* bindot, int dotlen);int main(int argc, char* argv[]){FILE *fp = fopen(font_file_name, "rb");int string_size = font_width * font_height;int i=0,j=0;unsigned char regcode; //区码unsigned char bitcode; //位码 // 计算区位码,regcode = (unsigned char) str[i] - subcode;bitcode = (unsigned char) str[i+1] - subcode;//再计算汉字在字库中的位置,进而得出此字符点阵在字体文件中的偏移int offset = ( (regcode-1) * reglen + bitcode-1) * dotsize;// 在字库文件中读取其点阵数据fseek(fp, offset, SEEK_SET);fread(bindot, sizeof(bindot),1, fp);//输出其点阵信息printcharbindot(bindot, dotsize);fclose(fp);system("pause");return 0;}//按顺序输出点阵的每一位信息void printcharbindot(char* bindot, int len){int charnum = 0; //当前字节号int bitnum = 0; //已读取的位数int bitindex =0; //当前位号int bitvalue; //当前位的值for (charnum =0; charnum < len; ++charnum){//从高到低顺次输出一个字节的每位信息for(bitindex = 7;bitindex>=0; --bitindex){//输出当前字节第bitindex位的值bitvalue = ((bindot[charnum]>>bitindex) & 0x1 ); printf("%c", bitvalue+'0');//满12位输出一行if ((++bitnum %12) == 0)printf("/n");}}}运行时用到的字库文件simsun12.fon可以到这里下载http://www.ugia.cn/wp-data/fontfun.rar运行结果为000000000000000000000000000000000000000000000000000000000100111111111110000000000000000000000000000000000000000000000000000000000000000000000000 转自:http://hi.baidu.com/boger/blog/item/3e36830182e7edd4277fb5fd.html