为什么需要混合输出 如何使用图形界面英-汉混合输出?我想这是困扰所有的学完汉字显示后的编程者所共同的问题。例如,对于ASCII字符来说,我不希望使用汉字全角的方式例如“AbCd”这样显示,一来显得不是太好看,二来占用信息是直接使用ASCII码的两倍,三来我们不习惯用全角输入英文字母,我们需要的是像“AbCd”这样的显示方式。 但是如果混合汉字的话,问题就出来了。因为若按全部为全角的方式显示还好办,例如“我是A,你的是多少?”这样的可以全部按照中文字模的计算方式来定位,其间隔也好控制。而我们有时输入时会成“我是A,你的是多少?”这样,麻烦就出来了。按汉字16*16点阵、ASCII码8*16点阵计算的话,其“我”字要占用16*16像素,而A只要8*16像素,而且他们一个是两个BYTE的汉字内码,一个是一个BYTE的ASCII码。如何处理就要费一番脑筋了。 低效率的方法 有人会想,这简单,就定义一个显示汉字的函数,用来显示其“我是”、“你的是多少”,另一个是显示ASCII码的函数,用来现实其“A”、“,”、“?”不就行了。结果一使用时,才发现要把他们的间距分配的很均匀并不是一件容易事。一来要计算水平位置5次,二来要连续写5个函数才能完成它的输出。这样的还好,因为中文比较连续,要是碰到“我A你B他C”这样的字符串呢?难道使用6次输出函数才能完成? 采用中-英文分开输出的函数效率低,那么有没有一种可以混合输出中-英文字符串的函数呢?答案是可以完成的。且听我来说说它的原理: 中-英文混合输出的原理 在《点阵汉字的显示》中请仔细看这句话“将ASCII表的高128个很少用到的数值以两个为一组来表示汉字,即汉字的内码。而剩下的低128位则留给英文字符使用,即英文的内码”。然后你会想到,这不就可以用一个判断来分开处理吗?如果你是这样想的话,那么,问题就解决了。对于中-英文混合输出来说,其关键问题就是对首次读取的字节按照其值的情况来确定它究竟是中文还是英文。如果读取的数值大于127的话,那么它是中文,需要继续读取下一个字节然后组成两字节的汉字内码然后显示汉字。如果小于或等于127的话,那么就把它当作英文ASCII码来显示吧。这不就行了吗? 一些注意 嗨,先别急。显示是这样就行了,但是要把不同字模大小的字放在一起,也不是那么轻松的。因为他们所需要的间距各不相同,你必须调整好你的间距设定,把英文字符的间距调整为中文间距的一半,这样就不会造成虽然字串字节相同但是显示出来字符长短不同的情况了。 还有,如果你将中文的英文的输出垂直位置选择在同一高度的话,那么显示出来将显得有点别扭,如果需要显示起来像WINDOWS里的那样美观的话,还需要调整ASCII字符的显示位置,将它定位得比汉字稍低一些。 输出代码 然后就开始练手了,在下面的演示程序里,对于ASCII码点阵字库的取得,我采用了读取字符ROM的方式,通过一个中断取得ASCII码字符ROM的首址,接下来的操作就跟读取ASCII字库文件的方式差不多了。这样可以少带一个ASCII字库文件运行。以下是程序代码: /*----------------------- cn_en.c -------------------------*/ /*中英文混合输出示例*/ #include "dos.h" #include "stdio.h" #include "graphics.h" char far* get_ascii_rom(unsigned int reg_bx)/*获得ROM字符集首址*/ {struct REGPACK reg; reg.r_ax=0x1130; reg.r_bx=reg_bx; intr(0x10,®); return MK_FP(reg.r_es,reg.r_bp); } void TextOutCn(int x,int y,unsigned char *s,int color) /*功能:中-英混合输出函数,在屏幕以(x,y)为左上角输出color色的s中-英混合字符串 限制:生成的EXE文件同级目录要有hzk16文件,否则其中的中文将看不到 */ {unsigned char mat[32],i,j,is_hz,can_put,far *ROM; unsigned long position; FILE *fp; ROM=get_ascii_rom(0x0600);/*获取8*16 ASCII字符ROM指针*/ fp=fopen("hzk16","rb");/*打开汉字库文件*/ while(*s!=0)/*开始输出文字循环*/ {if(*s>0xa0&&*(s+1)>0xa0)/*分支语句,判断当前指向的是中文还是英文内码*/ {/*若为中文读取中文字模*/ if(fp!=NULL)/*打开汉字库文件成功则拷贝中文字模到mat*/ {i=*s-0xa0;/*计算区号*/ j=*(s+1)-0xa0;/*计算位号*/ position=(94*(i-1)+(j-1))*32l;/*计算中文字模位置*/ fseek(fp,position,SEEK_SET);/*移动文件指针到字模位置*/ fread(mat,32,1,fp);/*读取为中文字模*/ } else memset(mat,0,32);/*否则将输出空白*/ is_hz=1;/*为中文*/ } else {/*若为英文读取英文字模*/ for(i=0;i<16;i++) {mat[i*2]=*(ROM+(*s)*16+i);/*字模左边8位为ASCII字模*/ mat[i*2+1]=0;/*字模右边8位补0*/ } is_hz=0;/*为英文*/ } /*开始输出字模了,将读取的中文或英文字模显示*/ for(j=0;j<16;j++) for(i=0;i<16;i++) if((0x80>>i%8)&mat[2*j+i/8])/*对于字模相应位为1则输出*/ putpixel(i+x,y+j+(1-is_hz)*4,color);/*将英文字模显示时下移4pixel,这样看起来美观些*/ if(is_hz) {x+=18;/*中文间距为18pixel*/ s+=2; } else {x+=9;/*英文间距为9pixel*/ s++; } } fclose(fp); } main() {int i=VGA,j=VGAHI; initgraph(&i,&j,""); TextOutCn(170,200,"Do you like it?我A你B他C",WHITE); TextOutCn(170,230,"中英混合输出演示!",CYAN); TextOutCn(480,440,"www.tc256.com",YELLOW); getch(); closegraph(); } 该函数仅为一简单演示,因此效率不是很高,若要提高效率则须避免反复打开汉字库文件和取字符ROM并采用无缓冲文件操作。有兴趣可以自己改写。
|