跳到主要内容

Unicode编码字符的点阵显示

·359 字·2 分钟

对于unicode编码的字符,可以先将unicode编码转换为GBK编码,然后利用GBK点阵字库(gbk.bin)显示字符。一个比较好的编码转换方法是,制作一个按照unicode编码顺序排列的GBK编码表,直接根据unicode编码就可以查到对应的GBK编码,具体的制作方法如下:

1.生成一个unicode字符文件 #

上以篇文章中已经制作了一个GBK编码的全字符文件gbk.txt,用记事本打开gbk.txt,然后以unicode编码另存为unicode.txt文件。

这样的话,所有的GBK编码字符都用unicode编码保存在unicode.txt中了,可以用winhex打开unicode.txt,会发现前两个字节是FFFE,这是unicode编码的标识,要注意后面的unicode编码是小端存储。

2.制作unicode转gbk的文件 #

这里要用程序制作一个unicode与gbk编码相对应的文件,该文件每四个字节为一组,其中前两个字节为unicode编码,后两个字节是对应的gbk编码,两种编码都以小端存储,数据结构如下:

union code

{

unsigned int unigbk;

unsigned short int uni_gbk[2];

unsigned char buffer[4];

};

这个数据结构是以gbk编码的顺序存放在文件uni2gbk.txt中,文件大小为128764Byte。程序如下:

//由unicode.txt和gbk.txt生成uni2gbk.txt
#include <stdio.h>

int main(void)
{
	unsigned char buffer[2];
	int count=0;

	FILE *fup=0;
	FILE *fgp=0;
	FILE *fwp=0;

	fup=fopen("unicode.txt","rb");
	fgp=fopen("gbk.txt","rb");
	fwp=fopen("uni2gbk.txt","wb");

	fgetc(fup);
	fgetc(fup);

	while(1)
	{
		//读取unicode编码,写入uni2gbk.txt
		buffer[0]=fgetc(fup);
		buffer[1]=fgetc(fup);
		fputc(buffer[0],fwp);
		fputc(buffer[1],fwp);
		//读取gbk编码,写入uni2gbk.txt
		buffer[0]=fgetc(fgp);
		buffer[1]=fgetc(fgp);
		fputc(buffer[1],fwp);
		fputc(buffer[0],fwp);

		count+=2;
		if(count==0xfb7c)
			printf("xxxxxxxxx/n");


		if(buffer[0]==0xfe && buffer[1]==0xfe)
		{
			printf("count = %x/n",count);

			fclose(fup);
			fclose(fgp);
			fclose(fwp);

			return;
		}
	}
	return 0;
}

3.将uni2gbk.txt排序 #

用程序将uni2gbk.txt文件中的union code数据结构按照unicode编码的顺序从小到大排序,程序如下:

#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE (0x7DBF)  //union code的个数

union code
{
	unsigned int unigbk;
	unsigned short int uni_gbk[2];
	unsigned char buffer[4];
};


int main(void)
{
	unsigned char flag=1;

	unsigned int i=0;
	unsigned int j=0;

	union code pdata;
	union code ndata;

	FILE *fp=0;

	fp = fopen("uni2gbk.txt","rb+");

	for(i=1; i<MAXSIZE && flag==1; i++)
	{
		flag=0;

		for(j=0; j<(MAXSIZE-i); j++)
		{
			fseek(fp,j*4,0);
			fread(pdata.buffer,1,4,fp);
			fseek(fp,j*4+4,0);
			fread(ndata.buffer,1,4,fp);

			if(pdata.uni_gbk[0]>ndata.uni_gbk[0])
			{
				flag=1;

				fseek(fp,j*4,0);
				fwrite(ndata.buffer,4,1,fp);
				fseek(fp,j*4+4,0);
				fwrite(pdata.buffer,4,1,fp);

			}

		}

		printf("i=%d/n",i);
	}

	fclose(fp);

}

排序后,为了与没有排序的uni2gbk.txt区分,将文件名改为uni2gbkp.txt。

4.删除无用的编码 #

用winhex打开uni2gbkp.txt,可以发现,从0到第0x80EB个字节中的unicode编码都是0x0020或0x003F,这些都是无用的编码,它们所对应的gbk编码也是无用的,都可以删除。

删除后,uni2gbkp.txt文件中的union code数据结构的unicode编码就是从0x00A4开始,以0xFFE5结束。但是这些unicode编码不是连续的,例如0x00A4之后就是0x00A7,为了方便查找,需要在不连续的编码中间用union code填充,对应的gbk编码部分用0x0000填充,然后将union code中的unicode编码全部删除。最后生成uni2gbk.bin文件。程序如下:

#include <stdio.h>
#include <stdlib.h>

union code
{
	unsigned int unigbk;
	unsigned short int uni_gbk[2];
	unsigned char buffer[4];
};

int main()
{
	unsigned short int count=0x00A4;  //从unicode的0x00A4开始
	union code temp;

	FILE *frp=0;
	FILE *fwp=0;

	frp=fopen("uni2gbkp.txt","rb");
	fwp=fopen("uni2gbk.bin","wb");

	fseek(frp,0x80EC,SEEK_SET);  //舍弃uni2gbkp.txt文件的前0x80EC个字节
	fread(temp.buffer,1,4,frp);

	while(count<=0xffe5) //以unicode的0xffe5结束
	{
		if(temp.uni_gbk[0]==count)     //判断unicode编码是否连续
		{
			fputc(temp.buffer[2],fwp);  //将对应的gbk编码写入uni2gbk.bin
			fputc(temp.buffer[3],fwp);
			fread(temp.buffer,1,4,frp);
		}
		else                        //不连续的地方填充0
		{
			fputc(0x00,fwp);
			fputc(0x00,fwp);
		}

		count++;
	}
	fclose(frp);
	fclose(fwp);
	return 0;
}

生成的uni2gbk.bin文件中都是gbk编码,这些gbk编码都是按照对应的unicode编码(0x00A4到0xFFE5)的顺序排列的。

5.uni2gbk.bin的使用 #

假设一个字符的unicode编码为X,那么它对应的gbk编码在uni2gbk.bin文件中的位置就是:

(X-0x00A4)*2

从这个位置读取一个unsigned short int数据,就是它的gbk码。然后利用GBK点阵字库(gbk.bin)即可显示。

例如,以Linux的终端模拟点阵屏幕,程序如下:

#include <stdio.h>
#include <unistd.h>
#include <curses.h>

#define START 0x8140
#define DATANUM 0x20

int displaychar(FILE *fp,unsigned short int dispch,char fillch,char start_x,char start_y);

int main(void)
{
	FILE * fp=0;
	unsigned short int testch = 0x7231;  //汉字'爱‘的unicode码
	unsigned short int gbkch=0;       //存放testch的gbk编码

	//将unicode转换为gbk
	fp = fopen("uni2gbk.bin","rb");
	fseek(fp,(testch-0x00A4)*((unsigned int)2),SEEK_SET);

	gbkch = fgetc(fp);
	gbkch = (fgetc(fp)<<8) + gbkch;

	fclose(fp);

	fp = fopen("gbk.bin","rb");

	initscr();

	displaychar(fp,gbkch,'*',0,0);

	refresh();

	while(1);
	endwin();

	fclose(fp);
	return 0;
}

/*
 * fp指向点阵字库二进制文件
 * 以点阵方式显示一个GBK字符
 * dispch是要显示的字符,fillch是填充点阵的字符
 * start_x,start_y是显示的起始坐标
 */
int displaychar(FILE *fp,unsigned short int dispch,char fillch,char start_x,char start_y)
{
	char x=start_x;
	char y=start_y;
	unsigned int location=(dispch-START)*DATANUM;

	int i=0;
	int j=0;
	char buf=0;

	fseek(fp,location,SEEK_SET);

	for(i=0;i<DATANUM;i++)
	{
		buf=fgetc(fp);

		//显示一个字节
		for(j=0;j<8;j++)
		{
			move(y+j,x);
			if( buf & (0x01<<j) )
			{
				addch(fillch);
			}
		}

		if(x == (start_x+15))
		{
			x=start_x;
			y=start_y+8;
		}
		else
			x++;
	}
	return 0;

}

下载: #

unicode点阵字库文件:http://download.csdn.net/source/3362591