正文

关于英文DOS下的汉字显示技术2006-05-16 21:23:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/mrli81/14204.html

分享到:

    一、汉字库结构及区位码   国家标准的汉字字符集(GB2312-80)在汉字系统中是以汉字库的形式提供的。汉字库中将汉字分成94个区,每个区有94个汉字,即所谓的“区”和“位”,每个汉字在字库中都有确定的区号和位号(用两个字节表示),这两个字节就叫做区位码。区位码的第一个字节表示区号,第二个字节表示位号。只要知道了汉字的区位码,就可以知道该汉字在汉字库中的位置。   二、汉字的内码   英文字符在计算机中是用一个字节的ASCII码表示的,该字节最高位一般用于奇偶校验,故实际是用7位码来代表128个字符的。即ASCII码的8个bit位中最高位是为0的,所以为了区分一个字节是汉字还是ASCII码,当汉字的国标码在机内表示时,将汉字国标码两字节的最高位均置1,以表示该码表示的是汉字。这个最高位置1的码就是常称的内码。   三、内码转换为区位码   区号 = 内码高位 - 0xa0   位号 = 内码低位 - 0xa0 若用十进制表示内码为c1c2,则区号(qh)和位号(wh)为:   qh = c1 - 160   wh = c2 - 160   (注: 160D = A0H) 即区位码(qw)为: qw = 100 * (c1-160) + (c2-160) 四、汉字库的制作   UCDOS 7.0里面有个“特显”功能,能显示任意宽度和任意高度的汉字。有相应的演示文件和原码都在“D:\UCDOS\SRC\TX\C”目录下,但其中演示文件在运行前,必须先敲一个“TX”命令,启动特显功能。   制作汉字库可以用以下方法:将所有汉字显示到屏幕上,每显示一个汉字时,将屏幕上的汉字区域截下来,存成二进制文件。)(当然要自己写程序):   1、 根据上面讲到的区位码与内码的对应关系,用下面的双重循环就可以显示94个区乘94个位的所有汉字。   ……   char   ch[3];   for( i = 0 ; i < 94 ; i ++ )   {     for( j = 0 ; j < 94 ; j ++ )     {         ch[0] = i + 0xa0 ;         ch[1] = j + 0xa0 ;         ch[2] = '\0' ;         SetTextColor(15,0);//(UCDOS7.0特显功能的设置颜色的函数;)         OutTextxy( 0 , 0 , ch ) ; //(UCDOS7.0特显功能中的一个显示汉字的函数;)     }   }   ……   很久以前写的一个做汉字库的小程序MKHZK.EXE,原代码没有找到,用得着的就来下载吧,由于这个破网站不能上传EXE文件,所以我把EXE文件放到了DOC文件里面,下载好DOC文件后打开来,再把里面的EXE文件复制出来就可以了.     以下是最近“翻箱捣柜”找到的几个函数,放阁这上面应该不会掉,否则下次就再也找不到了。 ////////////////////////////////////////////////////////////////////////// //                                               // //----------------------------------------------------------------------// //------------西文DOS下以画点.写显存方式显示汉字----(测试程序)----------// //----------------------------------------------------------------------// //                                               // // [说明]:                                       // //       此程序所用的汉字库为MKHZK.EXE所生成,且文件名格式必须为   // //                                               // //             "..\\hzk\\zk(高度)x(宽度)(字体)"             // //                                               // //       即字库路径必须为工作目录的上一级 hzk 目录中, 字库名必     // //       须为以上格式,如下例:                           // //                                               // //             "..\\hzk\\zk24x244"                     // //                                               // //       表示 24x24 点阵汉字,字体为宋体.                   // //                                               // //           上面的 puthz程序是画点显示函数(按照字模中的0与1的     // //       格式向屏幕上画点,其特点是显示速度慢);下面的 disphz 是     // //       直接写屏显示函数(直接将字模信息写入显存, 特点是显示速     // //       度快).                                   // //                                               // // [作者]: 黄 礼 进                                 // //                                               // // [日期]: 2001 年 12 月 14 日                           // //                                               // // ABCDEFGHIJKLMNOPQRSTUVWXYZ           // // [\/]^{|}~¢£ ̄¥0123456789<=>           // // ?#$%&@()^0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ           // //----------------------------------------------------------------------// ////////////////////////////////////////////////////////////////////////// #include<graphics.h>#include<alloc.h>#include<stdio.h>#include<stdlib.h>#include<dos.h>#include<string.h>#include<fcntl.h>#include<conio.h>#include<io.h>#include<mem.h>//#program inline /////////////////////////////////////////////////////////////////////////// //----------------------|| 画 屏 程 序 段 开 始 ||-----------------------// /////////////////////////////////////////////////////////////////////////// void far Clrscr(int left,int top,int right,int bottom,int color){       // 以指定的color颜色清除屏幕上的从left行top列到right行bottom列;  setfillstyle(SOLID_FILL,color);           // 设置图形的填充模式;  bar(left,top,right,bottom);             // 在指定的区域画实心框;} /////////////////////////////////////////////////////////////////////////// void far Button(int x1,int y1,int x2, int y2,int fg){// 在指定的x1行y1列到x2行y2列,按fg所指的类型画按扭框;int color1,color2;setfillstyle(1,7);// 设置图形的填充模式;bar(x1,y1,x2,y2); // 在指定的区域画实心框;if(fg==1){color1=15;color2=8;}else{color1=8;color2=15;}setcolor(color1);line(x1,y1,x2,y1);line(x1,y1,x1,y2);line(x1,y1+1,x2-1,y1+1);line(x1+1,y1,x1+1,y2); setcolor(color2);line(x1,y2,x2,y2);line(x2,y1,x2,y2);line(x1,y2-1,x2-1,y2-1);line(x2-1,y1,x2-1,y2-1);} /////////////////////////////////////////////////////////////////////////// void InitialGraphics(void)   //初始化图形模式;{int driver=DETECT,mode;int errorcode;registerbgidriver(&EGAVGA_driver);initgraph(&driver,&mode,"");errorcode=graphresult();if(errorcode!=grOk){  printf("Graphics error:%s\n",grapherrormsg(errorcode));  printf("Press any key to halt:");  getch();}} /////////////////////////////////////////////////////////////////////////////-------------------------------------------------------------------  //================================//  //   下 为 显 示 汉 字 程 序 段   //  //================================////-------------------------------------------------------------------/////////////////////////////////////////////////////////////////////////////用屏幕画点的方法显示汉字的程序.int puthz(int h,int w,int type,int space,  int isHorizontal,int slantingflag,int xPosition,  int yPosition,unsigned char *HZPTR,int color)  //w汉字的宽度;h汉字的高度;type字型号(字体);space字间距;//isHorizontal竖向显示标致;slantingflag汉字倾斜标致;xPosition 列坐标位置;  //yPosition 行坐标位置;HZPTR为所要显示的字符串;color汉字的颜色;{ ///////////slantingflag为斜体标致,1和2表示斜体(2比1斜得历害),0表示正体;int HZKFILE;                             //汉字库文件句柄;int HZSIZE,old_w;                           //字模数组长度;unsigned char HZKMAT[970];                   //存放字模的数组;char hzkname[80];                         //暂存库名的数组;char ch[8];               //临时数组,用于整型数到字符型数的转换;unsigned char qh,wh;                     //汉字的区号和位号;unsigned long offset;               //字库文件内部指针的定位标致;int xx;                               //暂存x坐标的变量;unsigned char mask[]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};register int i,j,k,x0,y0,pos;                 //只用于计数的变量;char test[80];unsigned char zm[16][2][8]; memset(HZKMAT,0,970);             //将数组HZKMAT中的所有元素清零;old_w=w; //将原始的 w 记下来,因为 w 的宽度不一定是汉字的宽度用于字间距;memset(hzkname,0,80);//将 hzkname 中的所有元素清零,为稳定性而加,可不要;strcpy(hzkname,"..\\hzk\\zk");//             \strcat(hzkname,itoa(h,ch,10));//             |strcat(hzkname,"x");//                     >--形成字库文件名;strcat(hzkname,itoa(w,ch,10));//             |strcat(hzkname,itoa(type,ch,10));//           / if((HZKFILE=open(hzkname,O_RDONLY|O_BINARY))==-1) //共享方式打开汉字库;{         //如果打不开汉字库则将最相似大小的字库打开并从中读取字模;if((w%8)>=1)  w=(w/8)*8+8;     //如果汉字的宽度模8大于等于1则算另外一个字节计算;else                             //即将宽度加上一个字节;  w=w/8*8;                 //否则其小于1的话,将原字节数计算;HZSIZE=w/8*h;                     //计算将要读取多少位字模; memset(hzkname,0,80);                   //将hzkname各元素清0;strcpy(hzkname,"..\\hzk\\zk");   //将存汉字库名的数组置最初的字符串;strcat(hzkname,itoa(h,ch,10));         //将汉字的高度拷贝至其后;strcat(hzkname,"x");                   //再拷贝一个 x 字符;strcat(hzkname,itoa(w,ch,10));         //将汉字的宽度拷贝至其后;strcat(hzkname,itoa(type,ch,10));//将汉字的字体拷贝到尾部,文件名做好;if((HZKFILE=open(hzkname,O_RDONLY|O_BINARY))==-1)     //打开汉字库;{                                 //若汉字库没有打开;  Clrscr(0,0,getmaxx(),getmaxy(),0);               //清除全屏;  printf("\nCan not open hzk !");     //输出文件没有打开的提示信息;  getch();                     //接受一个键盘输入(任意键);  closegraph();  exit(1);                         //函数返回 -1 出错标致;}}else                 //如果汉字库打开了,则计算其宽度,以读取字模;{if((w%8)>=1)  w=(w/8)*8+8;     //如果汉字的宽度模8大于等于1则算另外一个字节计算;else                             //即将宽度加上一个字节;  w=w/8*8;                 //否则其小于1的话,将按原字节数计算;HZSIZE=w/8*h;                     //计算将要读取多少位字模;}//---------------------------------------------------------------------  xx=xPosition;                       //将原始的列坐标暂存;while(*HZPTR!=NULL){if((*HZPTR&128)!=0)                 //判断其是否为汉字;{  if(isHorizontal==0)               //判断是否为横向显示;  {  if((xPosition+w+space)>=640&&*HZPTR!=NULL)  {             //如果当前的列坐标不能显示下一个汉字则换行;yPosition+=h+4,   //以上功能用当前x坐标加上汉字的宽度w再加xPosition=0;                   //上字间距space来实现;  }  }//如果列坐标超出了640,不能再显示下一个汉字时,而汉字又没有显示完,//则将列坐标重新设置为零,横坐标加上此行汉字的高度再加上4,目的是为了美观;  if(isHorizontal==1) yPosition+=h+space,xPosition=xx;  qh=HZPTR[0]-0xa0;//                     \  wh=HZPTR[1]-0xa0;//                     |   offset=(long)(94*(qh)+(wh))*HZSIZE;//       >--- 取字模;//   sprintf(test,"qh == 0x%x , wh == 0x%x , offset == %ld , HZSIZE == %d",qh,wh,offset,HZSIZE);  lseek(HZKFILE,offset,SEEK_SET);//           |  read(HZKFILE,HZKMAT,HZSIZE);//             /   y0=yPosition;//将汉字显示位置的行坐标暂存,以在显示下一汉字时用;  for( i=0 ; i<h ; i++ )       //从汉字的0行到汉字的高度循环;  {  x0=xPosition;   //将汉字显示的列坐标暂存,以在下一条显示时使用;  pos=w/8*i; //此行中的pos用于字模数组HZKMAT中下标定位,以取字模;  for(j=0;j<w;j++)                 //从0到汉字的宽度循环;  {if((mask[j%8]&HZKMAT[pos+j/8])!=NULL)//按位相与后不为0则画点;  if(slantingflag>=2)putpixel(x0+(h-i),y0,color);//断倾斜标致;  else if(slantingflag==1)putpixel(x0+(h/2-i/2),y0,color);  else putpixel(x0,y0,color); //屏幕当前坐标按颜色值画点;x0++;                       //画好后将列坐标加上1;  }  y0++;   //一行字模画完后将画下一行,y0++是将行数加1,到下一行;  }  xPosition+=old_w+space; //由于old_w是此函数的入口参数,是最标准;  HZPTR+=2; //的汉字宽度,HZPTR+=2是将要显示的字符串向后移两个字;}                         //节,因为汉字占用两个字节;else                               //如果不是汉字;//-------------以下是对ASCII码的显示方法及其控制--------------//{  if(isHorizontal==0)               //判断是否为横向显示;  {  if((xPosition + w + space)>=640&&*HZPTR!=NULL)  {             //如果当前的列坐标不能显示下一个汉字则换行;yPosition+=h+4;xPosition=0;     //以上功能用当前x坐标加上汉字的宽度w再加  }                           //上字间距space来实现;  }//如果列坐标超出了640,不能再显示下一个汉字时,而汉字又没有显示完,//则将列坐标重新设置为零,横坐标加上此行汉字的高度再加上4,目的是为了美观;  if(isHorizontal==1) yPosition+=h+space,xPosition=xx;//   offset=94*92+(HZPTR[0]-0x21);//取字库文件中ASCII码开始处偏移量;  offset = HZPTR[0]-0x21;  if(HZPTR[0] == ' ')//如果是空格跳转到一个没有字模的位置;offset = 92 * 94 + HZSIZE;  lseek(HZKFILE,offset*HZSIZE*1L,SEEK_SET); //移文件指针到字库文  read(HZKFILE,HZKMAT,HZSIZE);           //件ASCII码开始处;  y0=yPosition+h/8;//ASC显示位置的行坐标暂存,以在显示下一ASC时用;  //h/8 是为了将ASC字符显示位置降一点,以使其更美观;  for( i=0 ; i<h ; i++ )               //按ASC的高度循环;  {  x0=xPosition;//将ASC显示位置的列坐标暂存,以在显示下一条线时用;  pos=w/8*i;           //   pos用于HZKMAT数组中的下标定位;  for(j=0;j<w-1;j++)//按ASC的宽度循环, w-1是因为ASC没汉字那么宽;  {if((mask[j%8]&HZKMAT[pos+j/8])!=NULL)//按位相与后不为0则画点;  if(slantingflag>=2)putpixel(x0+(h-i),y0,color);//断倾斜标致;  else if(slantingflag==1)putpixel(x0+(h/2-i/2),y0,color);  else putpixel(x0,y0,color); //屏幕当前坐标按颜色值画点;x0++;                       //画好后将列坐标加上1;  }  y0++;   //一行字模画完后将画下一行,y0++是将行数加1,到下一行;  }  xPosition+=old_w-old_w/2+space;//ASC没汉字宽,所以减去8以缩字距;  HZPTR+=1;   //此处的字符指针只移一位,是因为ASC字符只占一个字节;}                         //(汉字占两个字节,所以加2);  }  close(HZKFILE);                       //关闭汉字库文件;return(0);                           //返加0值表示没有出错;} /////////////////////////////////////////////////////////////////////////   要想看的远,必须站的高,要站的高,必须基础牢!要不然摔下来就惨了...... [楼 主] | Posted: 2005-12-28 18:36     enjoyo    级别: 管理员精华: 2 发帖: 1010威望: 764 点金钱: 4227 RMB贡献值: 0 点在线时间:326(小时)注册时间:2005-08-29最后登录:2006-05-12         ///////////////////////////////////////////////////////////////////////// //以直接写显存的方式,向屏幕显示汉字; void disphz(int h,int w,int type,int space,       int isHorizontal,int Alignflag,int xPosition,     int yPosition,unsigned char *HZPTR,int color)       //w汉字的宽度;h汉字的高度;type字型号(字体);space字间距;   //isHorizontal竖向显示标致;xPosition 列坐标位置;yPosition 行坐标位置;             //HZPTR为所要显示的字符串;color汉字的颜色; // 当Alignflag为 1 时,为左对齐,为 -1 时为右对齐(此项功能仅针对于纯ASCII {       //码字符串),当汉字和ASCII码共处一串时,此功能在显示时可能不准确; int HZKFILE;                             //汉字库文件句柄; int HZSIZE;                               //字模数组长度; int stringlen=0; unsigned char HZKMAT[970];                   //存放字模的数组; char hzkname[80];                         //暂存库名的数组; char ch[8];               //临时数组,用于整型数到字符型数的转换; unsigned char qh,wh;                     //汉字的区号和位号; unsigned long offset;               //字库文件内部指针的定位标致; register int i,t; register long j; int s; char far *ptr;     stringlen=strlen(HZPTR); memset(HZKMAT,0,970);             //将数组HZKMAT中的所有元素清零; memset(hzkname,0,80);//将 hzkname 中的所有元素清零,为稳定性而加,可不要; strcpy(hzkname,"..\\hzk\\zk");//             \ strcat(hzkname,itoa(h,ch,10));//             | strcat(hzkname,"x");//                     >--形成字库文件名; strcat(hzkname,itoa(w,ch,10));//             | strcat(hzkname,itoa(type,ch,10));//           /     if((HZKFILE=open(hzkname,O_RDONLY|O_BINARY))==-1) //共享方式打开汉字库; {         //如果打不开汉字库则将最相似大小的字库打开并从中读取字模;   if((w%8)>=1)     w=(w/8)*8+8;     //如果汉字的宽度模8大于等于1则算另外一个字节计算;       //即将宽度加上一个字节;否则其小于1的话,将原字节数计算;   HZSIZE=w/8*h;                     //计算将要读取多少位字模;       memset(hzkname,0,80);                   //将hzkname各元素清0;   strcpy(hzkname,"..\\hzk\\zk");   //将存汉字库名的数组置最初的字符串;   strcat(hzkname,itoa(h,ch,10));         //将汉字的高度拷贝至其后;   strcat(hzkname,"x");                   //再拷贝一个 x 字符;   strcat(hzkname,itoa(w,ch,10));         //将汉字的宽度拷贝至其后;   strcat(hzkname,itoa(type,ch,10));//将汉字的字体拷贝到尾部,文件名做好;   if((HZKFILE=open(hzkname,O_RDONLY|O_BINARY))==-1)     //打开汉字库;   {                                 //若汉字库没有打开;     Clrscr(0,0,getmaxx(),getmaxy(),0);               //清除全屏;     printf("\nCan not open hzk !");     //输出文件没有打开的提示信息;   getch();                     //接受一个键盘输入(任意键);   closegraph();   exit(1);                         //函数返回 -1 出错标致;   } } else                 //如果汉字库打开了,则计算其宽度,以读取字模; {   if((w%8)>=1)     w=(w/8)*8+8;     //如果汉字的宽度模8大于等于1则算另外一个字节计算;     //即将宽度加上一个字节;否则其小于1的话,将按原字节数计算;   HZSIZE=w/8*h;                     //计算将要读取多少位字模; }         if((xPosition%8)>4) xPosition=xPosition/8+1;     else xPosition/=8;   if(Alignflag == -1)     if(((w/8)%2)!=0) xPosition -= stringlen * ((w/8+1)/2);     else xPosition -= stringlen * (w/8/2);     ptr=(char far *)0xa0000000l+80*yPosition+xPosition;     while(*HZPTR!=NULL)     {   if((*HZPTR&128)!=0)                 //判断其是否为汉字;   {   qh=HZPTR[0]-0xa0;//                     \   wh=HZPTR[1]-0xa0;//                     |   offset=(long)(94*(qh)+(wh))*HZSIZE;//         >--- 取字模;   lseek(HZKFILE,offset,SEEK_SET);//           |   read(HZKFILE,HZKMAT,HZSIZE);//             /         for(s=1; s<=(w/8*h); s++)     {       t = *ptr;     //将背景色暂存,稍候送入位屏蔽寄存器用来过滤;       outportb(0x3ce,0x05);   //将方式寄存器口地址送索引寄存器;       outportb(0x3cf,0x02);       //将方式寄存器的第二位置'1';       outportb(0x3ce,0x08);   //将位屏蔽寄存器口地址送索引寄存器;       outportb(0x3cf,HZKMAT[s-1]); //将字模信息送入位屏蔽寄存器;       *ptr = color;               //将前景色写入对应地址;       t = *ptr;     //将背景色暂存,稍候送入位屏蔽寄存器用来过滤;       outportb(0x3ce,0x08);   //将位屏蔽寄存器口地址送索引寄存器;       outportb(0x3cf,t);         //将背景色送入位屏蔽寄存器;       outportb(0x3ce,0x0005);         //恢复为缺省的写方式 0 ;       outportb(0x3ce,0x8ff08);         //位屏蔽寄存器不再屏蔽;           if(s%(w/8) != 0) //判断汉字写屏时在同一线上还是在下一线上;     ptr ++;   //在同一线上时,只用加上一字节,即可移到下一字节;       else ptr = ptr + 81 - w / 8; //当前线显示结束,移到下一线上;     }   HZPTR += 2;           //字符串中的汉字指针向后移两个字字;   if(isHorizontal==0)ptr=ptr-h*80+w/8+space;//判断是否为竖向显示;   else ptr = ptr + 80 + 80 * space;     //竖向显示时的处理方法;   }   else   {   offset=(HZPTR[0]-0x21);//取字库文件中ASCII码开始处的偏移;   if(HZPTR[0] == ' ')     offset = 92*94 + HZSIZE;   lseek(HZKFILE,offset*HZSIZE*1L,SEEK_SET); //移文件指针到字库文   read(HZKFILE,HZKMAT,HZSIZE);           //件ASCII码开始处;   for(s=1; s<=(w/8*h); s++)   {       t = *ptr;     //将背景色暂存,稍候送入位屏蔽寄存器用来过滤;     //     asm mov dl,0x05;   //     asm mov 0x3ce,dl;     // asm in al,dl;       outportb(0x3ce,0x05);   //将方式寄存器口地址送索引寄存器;       outportb(0x3cf,0x02);       //将方式寄存器的第二位置'1';       outportb(0x3ce,0x08);   //将位屏蔽寄存器口地址送索引寄存器;       outportb(0x3cf,HZKMAT[s-1]); //将字模信息送入位屏蔽寄存器;       *ptr = color;               //将前景色写入对应地址;       t = *ptr;     //将背景色暂存,稍候送入位屏蔽寄存器用来过滤;       outportb(0x3ce,0x08);   //将位屏蔽寄存器口地址送索引寄存器;       outportb(0x3cf,t);         //将背景色送入位屏蔽寄存器;       outportb(0x3ce,0x0005);         //恢复为缺省的写方式 0 ;       outportb(0x3ce,0x8ff08);         //位屏蔽寄存器不再屏蔽;           if(s%(w/8) != 0)   //判断ASC写屏时在同一线上还是在下一线上;     ptr ++;   //在同一线上时,只用加上一字节,即可移到下一字节;       else ptr = ptr + 81 - w / 8; //当前线显示结束,移到下一线上;   }   HZPTR ++;               //ASC只占一个字节,所以只用加加;   if(isHorizontal==0)   //判断,如果是横向显示则'字间距'如下处理;   {     if((w/8%2)==0) ptr = ptr - h * 80 + w / 8 / 2 + space;     else ptr = ptr - h * 80 + (w / 8 + 1) / 2 + space;   }   else ptr=ptr+80+80*space;     //竖向显示时对字间距的处理方法;   }     }   close(HZKFILE);                       //关闭汉字库文件; }     ///////////////////////////////////////////////////////////////////////     //------------------|| 汉 字 显 示 程 序 结 束 ||--------------------//     ///////////////////////////////////////////////////////////////////////     void main(void) {   int i,j;       InitialGraphics(); // Button(0,0,getmaxx(),getmaxy(),1);   puthz(16,16,4,1,0,1,10,10, "abc ABC`1234567890-=[]\\;',./黄~!@#$%^&*()_+{}|:\"<>?礼进",15);   puthz(16,16,4,1,0,0,10,30,"abcdefghijklmnopqrstuvwxyz 我左边有一个空格哦",2);   puthz(24,24,1,1,0,0,10,50,"ABCDEFGHIJKLMNOPQRSTUVWXYZ 我左边有一个空格哦!",2);   puthz(32,32,3,1,0,0,10,70,"长江之水天上来!",2);   puthz(40,40,3,1,0,0,10,90,"这是我的一个测试程序.",2); /* puthz(40,40,1,1,0,0,122,232,"长江之水天上来",4);     puthz(40,40,2,2,1,0,52,15, "长江之水天上来",0); puthz(40,40,2,2,1,0,42,9,   "长江之水天上来",14);     puthz(40,40,2,2,1,0,560,15, "奔流到海不复回",0); puthz(40,40,2,2,1,0,550,9, "奔流到海不复回",14);     puthz(48,48,4,0,0,0,122,282,"长江之水天上来",2); puthz(48,48,4,0,0,2,122,342,"长江之水天上来",0); puthz(48,48,4,0,0,0,122,342,"长江之水天上来",14); puthz(80,80,2,0,0,0,15,390, "长江之水天上来",2);     getch(); setfillstyle(1,1); Clrscr(0,0,getmaxx(),getmaxy(),0); Ltan(0,0,getmaxx(),getmaxy(),1); */ disphz(16,16,4,0,0,1,80,18, "长江abc ABC 123 !@# 之水天上来",10); disphz(16,16,4,0,0,1,80,35, "长江之水天上来",2); // disphz(24,24,1,0,0,1,80,55, "长江之水天上来abcdefg",4); disphz(32,32,2,0,0,1,80,80, "长江之水天上来",4); disphz(40,40,3,0,0,1,80,114,"长江之水天上来",5); disphz(48,48,4,0,0,1,80,158,"长江之水天上来",11); /* disphz(56,56,1,0,0,1,80,203,"长江之水天上来",10); disphz(64,64,3,0,0,1,80,261,"长江之水天上来",9); disphz(80,80,2,0,0,1,80,340,"长江之水天上来",14); disphz(32,32,4,0,0,1,80,423,"ABCDEFGHIJKLMNOPQRSTUVWXYZ",12); disphz(24,24,4,0,0,1,80,455,"abcdefghijklmnopqrstuvwxyz",2); disphz(64,64,2,0,1,1,18, 17,"长江之水天上来",0); disphz(64,64,2,0,1,1,2, 10, "长江之水天上来",14); */   puthz(16,16,4,0,0,0,0,50,"黄 礼进abcABC`123~!@#$%^&*()_+-=[]\{}|;':\",./<>?黄我的字体测试程序!",10);   puthz(32,32,3,0,0,0,0,300,"黄 我的字体测试程序!",10);     // GetZMToFile(16,16,4,"dispinformation3","[<是否禁用详细信息>]","dispinfo.c"); // Puthz(16,16,200,200,"错误:请先运行UCDOS7.0的特显功能!",&noruntx[0][0],10); // ChangeFile("c:\\borlandc\\bin\\mkhzk2.c","t_tt.c");   puthz(16,16,4,1,0,0,10,400, "abc ABC`1234567890-=[]\\;',./黄~!@#$%^&*()_+{}|:\"<>?礼进",15);   getch();   Clrscr(0,0,getmaxx(),getmaxy(),0);   closegraph(); }   要想看的远,必须站的高,要站的高,必须基础牢!要不然摔下来就惨了...... [1 楼] | Posted: 2005-12-28 18:37     enjoyo    级别: 管理员精华: 2 发帖: 1010威望: 764 点金钱: 4227 RMB贡献值: 0 点在线时间:326(小时)注册时间:2005-08-29最后登录:2006-05-12         1、 什么叫字模,以及怎样得到字模。 (1)、每个汉字在屏幕上显示的时候,都会占用屏幕上的一个小矩形区域,这个矩形区域是由屏幕上集中在一个矩形区的像素点组成的,在DOS环境里,这组像素点有的为黑色,有的为白色,所有黑色点(或白色的点)的路径描绘出汉字的轮廓,让我们得以识别,而这组点阵信息在机内是怎样表示的呢,根据字体的大小,比如一个宽度为16像素,高度也为16像素的“大”字,就要占用16×16=256个像素点,这256个像素点呈矩形排列,横向16个点,纵向16个点,而16个点,刚好用两2个字节完全表示,而亮的点用二进制里的“1”表示,暗的点用二进制里的“0”表示,即会出现下面的矩阵:     高八位       低八位 □□□□□□■■□□□□□□□□ □□□□□□■■□□□□□□□□ □□□□□□■■□□□□□□□□ □□□□□□■■□□□□□■□□ ■■■■■■■■■■■■■■■□ □□□□□□■■□□□□□□□□ □□□□□□■■□□□□□□□□ □□□□□□■■□□□□□□□□ □□□□□□■■□□□□□□□□ □□□□□□■■■□□□□□□□ □□□□□■■□□■□□□□□□ □□□□■■□□□□■□□□□□ □□□■■□□□□□□■□□□□ □□□■□□□□□□□■■□□□ □□■□□□□□□□□□■■■□ ■■□□□□□□□□□□□■□□       高八位       低八位     高字节编号 字模 低字节编号 字模 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0     0     0x03     1     0x00 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0     2     0x03     3     0x00 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0     4     0x03     5     0x00 0 0 0 0 0 0 1 1 0 0 0 0 0 1 0 0     6     0x03     7     0x04 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0     8     0xFF     9     0xFE 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0     10     0x03   11     0x00 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0     12     0x03   13     0x00 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0     14     0x03   15     0x00 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0     16     0x03   17     0x00 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0     18     0x03   19     0x00 0 0 0 0 0 1 1 0 0 1 0 0 0 0 0 0     20     0x06   21     0x40 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0     22     0x0C   23     0x20 0 0 0 1 1 0 0 0 0 0 0 1 0 0 0 0     24     0x18   25     0x10 0 0 0 1 0 0 0 0 0 0 0 1 1 0 0 0     26     0x10   27     0x18 0 0 1 0 0 0 0 0 0 0 0 0 1 1 1 0     28     0x20   29     0x0E 1 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0     30     0xC0   31     0x04 从上图中可以看出,一个16×16点阵的汉字,需要32个字节存放字模。看到这里,应该能明白什么叫字模了。你可以把它理解为是用于显示汉字用的一组模子,它由二进制的“0”或“1”标记屏幕上的白点或黑点,以此勾画汉字的轮廓。 (2)、怎以得到字模,形成汉字库呢。在DOS下,当屏幕初始化为640×480像素16色模式时,屏幕上共有480(0-479)行,每一行有640(0-639)个点,而640个像素点,每个点用一个二进制位表示,则刚好可以用640/8=80个字节来表示。现在假设显示模式为单色模式,暂别管16色,即屏幕上只能显示黑点或者白点,那么满屏的图像就有(80×480)=(38400)个字节,这38400个字节的值怎么得到呢,很简单,因为显存的起始地址是0xa0000000,38400个字节,只用依次往上加就可以了。如下图:     屏幕第000行地址:0xA0000000 0xA0000001 0xA0000002 …… 0xA000004F 屏幕第001行地址:0xA0000050 0xA0000051 0xA0000052 …… 0xA000009F ……………… 屏幕第439行地址:0xA00088E0 0xA00088E1 0xA00088E2 …… 0xA00095FF     现在假设有一个16×16的汉字显示在屏幕的0行0列,那么它的字模地址就会分布在:     屏幕第000行地址:0xA0000000 0xA0000001 屏幕第001行地址:0xA0000050 0xA0000051 ……………… 屏幕第015行地址:0xA0000460 0xA0000461     于是只用将这些地址对应的值依次存起来就形成了这个汉字的字模,因此,如果将94个区94个位的所有汉字在屏幕上的0行0列显示一遍,并且每显示一个汉字就存下这个汉字的字模到文件。这样就形成了一个16×16点阵字的字库。 同样原理,如果要制做一个24×24点阵的字库,依次将所有汉字显示到0行0列,每显示一个就存储下面地址对应的值就可以了:     屏幕第000行地址:0xA0000000 0xA0000001 0xA0000002 屏幕第001行地址:0xA0000050 0xA0000051 0xA0000052 ……………… 屏幕第023行地址:0xA0000730 0xA0000731 0xA0000732     在16色模式下,因为每个点可以显示16种颜色,而16种颜色刚好可以用4位二进制数完全表示,因此屏幕上每个像素点实际上需要4个二进制位来表示,即满屏图像信息需要占用(480×80×4)=(38400×4)=153600个字节。这个你不必担心,因为每机器把153600个字节分成了4个独立的单色位面,每个单色位面占38400个字节,4个单色位面叠加起来就复合成了彩色的。(你可以把它想象成一个[640×480×4]的三维矩阵,从正面看,它就是一个[640×480]的位面,从左侧看,是一个[4×480]的矩阵,表示的是屏幕最左边一列的颜色信息,每一个像素点占4个二进制位,第0位面为高位,第3位面为低位,这个4位二进制数的值就是对应着从正面看时,该点的颜色号),第个位面的起始地址还是0xA0000000,只不过在16色模式下,需要选位面存字模。 怎么样选位面呢。可以通过EGA/VGA适配器上的图形控制器的两个寄存器,即方式寄存器和位屏蔽寄存器,图形控制器上共有9个寄存器,编号如下: 索引号   寄存器名称 00     设置/清除寄存器 01     设置/清除允许寄存器 02     颜色比较寄存器 03     数据旋转移动与功能选择寄存器 04     读颜色位面选择寄存器 05     方式寄存器 06     混合寄存器 07     颜色无关寄存器 08     位屏蔽寄存器 为了减少I/O口地址数量,它们共用一个口地址,这个口地址可以重复使用,另外还有一个索引寄存器(其口地址为0x3CE),如上表,9个内部寄存器分别有自己的索引号,它们共用一个口地址0x3CF,当给索引寄存器写入一个索引号后,其后对0x3CF口地址的读或写操作,就是对由索引号指定那个寄存器进行的操作,这样就实现了口地址的复用,总之,索引寄存器的口地址为0x3CE,9个寄存器的口地址为共用的口地址0x3CF。 在上面表中可以看出“位面选择寄存器”的索引号是4,因此先将索引号“4”送入索引寄存器,表示接下来要选位面,再将位面号(0-3)送入共用的口地址0x3CF,即选择所需要的位面,但选择时要保证选择的是有颜色信息的位面。因为4个位面的值根据当前的颜色会有所不同,为了防止选中无颜色的位面,最好的方法是在显示汉字的时间用白色,这样所有位面上的值都是一样的了。随便选一个也会得到字模。但要注意,最后读完字模后,一定要关掉0x3CF口的当前寄存器号,即向0x3CF口地址送一个“0”就可以了。  

阅读(4921) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册