Turbo C程序中点阵汉字库和曲线汉字库的显示
在Turbo C语言教学和程序开发中,经常遇到要在屏幕显示汉字问题。早期windows95、windows 98时期可借助UCDOS汉字平台,在TC程序中显示汉字,而今,在windows xp、windows 2000中,由于兼容性问题,无法安装和运行UCDOS,因而TC程序中不能直接显示汉字了。本文介绍TC程序中,进入图形模式,无需任何汉字平台支持,直接读取汉字库字模信息,用TC画点函数putpixel(考虑到通用性,没有使用显卡特性和显示寄存器加速输出)显示多种字库汉字。本文仍用UCDOS 16点阵、24点阵、48点阵、曲线轮廓(postscript)汉字库和西文16点阵、西文曲线轮廓字库(字库文件名依次为 hzk16、hzk24k、hzk48s、hzkpsxk、asc16、ascps)为例,编程实现西文状态下的汉字显示。为此,我们必须首先了解UCDOS字库文件结构和读取步骤。其次是编程算法和思路以及必要条件。
一、点阵字库结构和读步骤
1 先根据一个汉字高字节机内码计算出区码(QM),再根据低字节计算出位码(WM);
(设汉字串指针为 hzstr已指向一个汉字首字节)
2 由区码和位码计算汉字字模信息在字库文件中的索引位置(record);
3 由索引值计算字模信息在字库文件中的起始偏移量(point);
4 定位文件位置指针到起始偏移量处,连续读取单字点阵字节数到缓冲区(buf)。
计算公式分别是:
1)QM=(hzstr-0xa0)&0x7f,WM=((hzstr+1)-0xa0)&0x7f
2) record=(QM-16)94+(WM-1) 注意:16点阵时 record=(QM-1)94+(WM-1)
3) point=recordsize
其中:size为不同点阵汉字字节数,16点阵size=32,24点阵size=72,48点阵size=288
西文字库偏移量比较简单,公式为 point=asc16
其中 asc为要显示的单个西文字符,因为西文字符是单字节,故size=16
二 postscript曲线轮廓字库结构和读取步骤
首先,此种字库结构比点阵字库复杂许多,它存储的是一些控制如何画线及其坐标信息。每个曲线轮廓字库都两部分组成: 汉字索引区、字型数据区。汉字索引区由许多索引项组成。每个索引项由六个字节组成, 其中字型数据的偏移地址4 个字节, 字型数据的长度占2 个字节。由汉字的索引提供的字型数据偏移地址及字型数据的长度即可得到该汉字的字型数据。为了确定一个汉字在字库汉字索引区的偏移量, 由汉字机内码或区位码即可求得汉字在曲线轮廊字库索引区中的偏移量, 计算方法如下:
- 区码QM和位码WM以及索引值的计算与点阵字库相同
2 )偏移量OFFSET=record*6
而英文字体(字库名为 ASCPS)的偏移量比较特殊,它共有lO种字体,每种字体有1O0个英文字符,可以这样确定偏移量(设字体号为N ,英文字符的ASCII码为CC):
offset=(N*100-(CC-32))*6
在UCDOS 5.0 中从此偏移量连续读取4 个字节转换成长整型数, 即为字型数据地址(Address ) , 紧接着
3 个字节转换成整型数便为字型数据的长度(Length )。
在UCDOS 6.0 中从此偏移量地址连续读取4 个字节转换成长整型数后, 还需将此长整型数减去十六进制
0x10000000 后才为字型数据地址, 紧接着2 个字节转换成整型数便为字型数据的长度(Length ),包括符号库。但英文字符不需要调整。
4、字型数据的格式
三次曲线字库的字形数据需要解释和重组。读取三次曲线字库的字形数据时每次只能读取四位,方法是当某一字节第一次被读取时, 读取低四位,当该字节再次被读取时, 读取高四位。当读取的数据不需要被当做坐标量时, 读取的四位数据就会被当做命令(控制字),并进行解释。如果当前命令需要坐标量, 坐标量分为绝对坐标值和坐标增量。绝对坐标值为一个字节, 为读取的两个四位数据的重组, 重组方法为先读取的四位数据作为高四位, 后读取的四位数据作为低四位。坐标增量为四位或六位的二进制数, 其中最高位为符号位。四位坐标增量为当前读取的四位数据。坐标增量为六位二进制数时同样是通过重组得到的, 方法是将第一次读取的四位数据作为六位数据的高四位, 第二次读取的四位数据的高两位作为六位数据的低两位, 得到第一个坐标增量,然后将第二次读取的四位数据的低两位作为六位数据的高两位, 第三次读取的四位数据作为六位数据的低四位, 得到第二个坐标增量。
5、控制字的含义
UCDOS 的控制字为4 位(半字节) , 共有16 种不同功能的控制字, 分别控制产生曲线轮廊字型的不同曲线
段。具体含义如下:
表1 控制字的含义及功能
说明: ①参数X1, Y1, X2, Y2, X3, Y3 均表示8 位长度的坐标值, 且为正数, 表示范围为0 至255;
②参数# X1,# Y1,# X2,# Y2,# X3,# Y3 均表示长度相对当前点的增量, 最高位是符号位,0 表示正数,1 表示负数, 表示范围为-7 至+7;
③参数&X1, &Y1, &X2, &Y2, &X3, &Y3 均表示6 位长度相对当前点的增量, 最高位是符号位,0 表示正数,1 表示负数, 表示范围为-31 至+31;
④CX, CY 均表示当前点的坐标值。
三 编程思路
1 对于点阵字库:打开相应字库文件,根据汉字机内码计算其区位码,由区位码计算汉字索引号,由索引号乘字模字节数计算汉字在字库文件中的偏移量,从此偏移处读取相应字节数到内存缓冲,依行、列、位三重循环用putpixei函数画点显示之。
2 对于曲线字库:打开相应字库文件,由区位码计算汉字索引号,从文件索引号处读取4字节偏移量和2字节字模长度数据,再从文件偏移处读取长度字模数据到内存缓冲,将缓存中每字节高低四位易位,从中获取4位控制字(0到15共16种状态),根据其不同值确定是画线段或画矩形框,或拟合成贝塞尔曲线下的若干线段,计算端点或顶点坐标后画之。
四 说明
1本程序在windows xp平台下TC2.0 IDE环境中编译运行通过。
2需准备的UCDOS字库文件有:hzk16,asc16,ascps,hzk24k,hzk48s,hzkpsxk,egavga.bgi且保存到程序文件同一目录下。3 本程序使用的hzk24k,hzk48s均为显示字库文件,同名的打印字库字模须作旋转90度处理方可正确显示。4 要显示的字串可以中西文混杂,均能正确显示。5 之所用UCDOS 西文字库,是因为其显示西文时更圆滑,更美观,少锯齿。
#include<stdio.h>
#include<graphics.h>
#include<conio.h>
#include<alloc.h>
#include<math.h>
typedef unsigned char UC;
typedef unsigned int UI;
void graph_mode(); /*进入TC图形模式(640x480x16)函数*/
void posthz(UC *hzstr); /*Postscrip曲线汉字库显示预备函数*/
void hz16(UC *hzstr,int x,int y,int color); /*16点阵汉字库显示函数*/
void asc16(UC *asc,int x,int y,int color); /*16点阵西文字库显示函数*/
void hz24k(UC *hzstr,int x,int y,int color);/*24点阵汉字库显示函数*/
void hz48s(UC *hzstr,int x,int y,int color);/*48点阵汉字库显示函数*/
void showhz( UC *hzstr,FILE *hz,char *fname,FILE *ascp);/*曲线字库显示函数*/
int topdot[4096][2]={0};/*多边形顶点数组*/
UI Fill=0; /*封闭图形填充标志,为0只显示字符轮廓,为1字符内部填充*/
UI top; /*多边形顶点计数*/
main()
{
UC *text="宁乡师范学校对口升学C语言";
UC *asc="College entrance examination for vocational school students";
graph_mode();
hz16("16点阵宋体显示字库演示:",10,80,14);
hz16(text,10,100,12);
hz16("16点阵西文显示字库演示:",10,150,14);
asc16(asc,10,170,15);
hz16("24点阵楷体显示字库演示:",10,210,14);
hz24k(text,10,230,10);
hz16("48点阵宋体显示字库演示:",10,300,14);
hz48s(text,10,320,13);
hz16("按任意键开始曲线轮廓大字显示...",10,390,14);
getch();
cleardevice();
posthz(text);
closegraph();
textattr(0x07);
clrscr();
}
/*******************************/
void graph_mode() /*TC图形模式初始化*/
{ int gdrive=DETECT,gmode,ecode;
initgraph(&gdrive,&gmode,"");
ecode=graphresult();
if(ecode!=grOk)
{ printf("Graphics error: %s\n",grapherrormsg(ecode));
getch();
exit(0);
}
setcolor(15);
setbkcolor(0);
cleardevice();
directvideo=1;
}
/*******************************/
void posthz(UC *hzstr)
{
FILE *hz,*ascp;
char *fname1="hzkpsxkj";/*曲线汉字库文件名(行楷简)*/
char *fname2="ascps"; /*曲线西文字库文件名*/
if((hz=fopen(fname1,"rb"))==NULL) /*打开曲线汉字库文件*/
{ printf("UCDOS postscrtpt file %s open fail!\n",fname1);
getch();
return;
}
if((ascp=fopen(fname2,"rb"))==NULL) /*打开曲线西文字库文件*/
{ printf("UCDOS postscrtpt file %s open fail!\n",fname2);
getch();
return;
}
rewind(hz);
rewind(ascp);
showhz(hzstr,hz,fname1,ascp);/*显示曲线字串*/
fclose(hz);
fclose(ascp);
}
/***************************************/
void showhz(UC *hzstr,FILE *hz,char *fname,FILE *ascp)
{
#define Bit8 8 /*二进制位宏*/
#define Bit6 6
#define Bit4 4
void bezier_3(int *x,int *y);/*二次贝塞尔(bezier)曲线函数*/
void bezier_4(int *x,int *y); /*三次贝塞尔(bezier)曲线函数*/
UC getbit(UI *n,UI b,UC *bitbuf);/*取二进制位函数*/
UI getint( int num,double scl);/*四舍五入取整函数*/
UC *bitbuf,*dotbuf; /*位缓冲区和点缓冲区指针*/
double scalex=3.4,scaley=3;/*汉字水平和垂直放大因子*/
typedef struct /*曲线字库中汉字信息索引结构体*/
{ long fontoffset; /*字模偏移量*/
int fontlength; /*字模信息长度*/
}INDEX;
INDEX fontdata={0L,0};
int QM,WM; /*汉字区码和位码*/
long offset;
int z1,i,j;
UI loop;
int xx[4],yy[4],x1,y1,x2,y2,x3,y3,cx=0,cy=0;/*cx,cy为画笔当前点坐标(即起点)xx,yy为顶点坐标数组*/
UC dx4,dy4,dx6,dy6,tmp,data,ctrl_word;/*分别为4位、6位、坐标增量及控制字*/
FILE *fp;
/* for(QM=16;QM<88;QM++) 此注释可显示字库中全部汉字*/
for(WM=1;WM<95;WM++)
*/
while(*hzstr) /*显示串中所有汉字*/
{
if(*hzstr<160) /*若为西文,则用西文字库显示*/
{ fp=ascp;
offset=(4*100-(*hzstr-32)-17)*6;hzstr++; /*确定西文偏移*/
}
else /*否则,用汉字库显示*/
{
fp=hz;
QM=(*hzstr-0xa0)&0x7f; /*计算汉字区码*/
WM=(*(hzstr+1)-0xa0)&0x7f;/*计算汉字位码*/
offset=((QM-16)*94+(WM-1))*6L;/*计算汉字在字库中的索引*/
hzstr+=2;
}
fseek(fp,offset,SEEK_SET);
fread(&fontdata,sizeof(fontdata),1,fp);/*读索引信息*/
fseek(fp,fontdata.fontoffset,SEEK_SET);
dotbuf=(UC *)malloc(fontdata.fontlength*sizeof(char)+10);/*分配动态内存*/
if(!dotbuf){printf("memory Not\n");getch();return;}
z1=fontdata.fontlength;
if(fread(dotbuf,1,z1,fp)!=z1) /*从字库文件中读字模信息*/
{ printf("End of %s file\n",fname);getch();return;}
bitbuf=(UC *)malloc(8*z1*sizeof(char)+10);
if(!bitbuf){printf("memory overflow!\n");getch();return;}
for(i=0;i<z1;i++) /*字模各字节高低四位易位*/
dotbuf[i]=(dotbuf[i]<<4)|(dotbuf[i]>>4);
loop=0;
for(i=0;i<z1;i++)
for(j=0;j<8;j++)
bitbuf[loop++]=(dotbuf[i]>>(7-j))&1; /*将字模信息各二进制位存数组*/
loop=top=0;
while(loop<8*z1)
{ ctrl_word=getbit(&loop,Bit4,bitbuf); /*计算4位控制字*/
if((loop>5)&&Fill&&(ctrl_word==0))/*如果画一个多边形开始*/
{ setcolor(15);
if(getpixel(topdot[0][0],topdot[0][1])==12)/*红色点说明已填充*/
setfillstyle(1,0);/*已填红色汉字内多边形孤岛用黑色填充*/
else
setfillstyle(1,12);/*若多边形内无孤岛则用红色填充*/
fillpoly(top-1,(int far *)topdot); /*画多边形并填充*/
top=0;/*画完一个多边形后顶点数重回0*/
}
if(ctrl_word)setcolor(ctrl_word); /*设置画线颜色*/
switch(ctrl_word) /*根据控制字(4位二进制表示0到15)确定连线点坐标及如何画线*/
{
case 0:
x1=getbit(&loop,Bit8,bitbuf);/*从位缓冲取8位绝对x坐标*/
y1=getbit(&loop,Bit8,bitbuf);/*取8位绝对y坐标*/
x1=getint(x1,scalex); /*x坐标放大scalex倍后四舍五入取整*/
y1=getint(y1,scaley);/*y坐标放大scaley倍*/
if(Fill){topdot[top][0]=x1;topdot[top++][1]=y1;}/*若填充时将x1,y1存入多边形顶点数组*/
else moveto(x1,y1);/*只移动画笔*/
cx=x1;cy=y1;/*确定画笔当前点坐标*/
break;
case 1:
x1=getbit(&loop,Bit8,bitbuf);
x1=getint(x1,scalex);
if(Fill){topdot[top][0]=x1;topdot[top++][1]=cy;}
else line(cx,cy,x1,cy);/*二点画水平直线段*/
cx=x1;
break;
case 2:
y1=getbit(&loop,Bit8,bitbuf);
y1=getint(y1,scaley);
if(Fill){topdot[top][0]=cx;topdot[top++][1]=y1;} /*若要填充,线段末端坐标存多边形顶点数组*/
else line(cx,cy,cx,y1);/*画垂直直线段*/
cy=y1;
break;
case 3:
x1=getbit(&loop,Bit8,bitbuf);
y1=getbit(&loop,Bit8,bitbuf);
x1=getint(x1,scalex);
y1=getint(y1,scaley);
if(Fill){topdot[top][0]=x1;topdot[top++][1]=y1;}
else line(cx,cy,x1,y1);/*画斜线段*/
cx=x1;cy=y1;
break;
case 4:
x1=getbit(&loop,Bit8,bitbuf);
y1=getbit(&loop,Bit8,bitbuf);
x2=getbit(&loop,Bit8,bitbuf);
y2=getbit(&loop,Bit8,bitbuf);
x1=getint(x1,scalex);
y1=getint(y1,scaley);
x2=getint(x2,scalex);
y2=getint(y2,scaley);
xx[0]=cx;yy[0]=cy;
xx[1]=x1;yy[1]=y1;
xx[2]=x2;yy[2]=y2;
cx=xx[2];cy=yy[2];
bezier_3(xx,yy); /*三个顶点画二次贝塞尔曲线*/
break;
case 5:
x1=getbit(&loop,Bit8,bitbuf);
y1=getbit(&loop,Bit8,bitbuf);
x2=getbit(&loop,Bit8,bitbuf);
y2=getbit(&loop,Bit8,bitbuf);
x3=getbit(&loop,Bit8,bitbuf);
y3=getbit(&loop,Bit8,bitbuf);
x1=getint(x1,scalex);y1=getint(y1,scaley);
x2=getint(x2,scalex);y2=getint(y2,scaley);
x3=getint(x3,scalex);y3=getint(y3,scaley);
xx[0]=cx;yy[0]=cy;
xx[1]=x1;yy[1]=y1;
xx[2]=x2;yy[2]=y2;
xx[3]=x3;yy[3]=y3;
cx=xx[3];cy=yy[3];
bezier_4(xx,yy);/*四个顶点画三次贝塞尔曲线*/
break;
case 6:
x1=getbit(&loop,Bit8,bitbuf);
y1=getbit(&loop,Bit8,bitbuf);
x2=getbit(&loop,Bit8,bitbuf);
y2=getbit(&loop,Bit8,bitbuf);
x1=getint(x1,scalex);y1=getint(y1,scaley);
x2=getint(x2,scalex);y2=getint(y2,scaley);
rectangle(x1,y1,x2,y2);/*画矩形框*/
break;
case 7:
dx4=getbit(&loop,Bit4,bitbuf); /*从缓冲取4位坐标改变量*/
y1=getbit(&loop,Bit8,bitbuf);
y1=getint(y1,scaley);
dx4&=0x0f; /*取低4位改变量*/
tmp=dx4&0x07;/*取低3改变量绝对值*/
tmp=getint(tmp,scalex);
if(dx4&8)x1=cx-tmp;/*取4位中最高位若为1,则改变量为负*/
else x1=cx+tmp; /*否则改变量为正*/
if(Fill){topdot[top][0]=x1;topdot[top++][1]=y1;}/*若要填充,线段末端点存多边形顶点数组*/
else line(cx,cy,x1,y1);/*从画笔当前点(cx,cy)至(x1,y1)画直线段*/
cx=x1;cy=y1;
break;
case 8:
x1=getbit(&loop,Bit8,bitbuf);
x1=getint(x1,scalex);
dy4=getbit(&loop,Bit4,bitbuf);
dy4&=0x0f;
tmp=dy4&0x07;
tmp=getint(tmp,scaley);
if(dy4&8)y1=cy-tmp;
else y1=cy+tmp;
if(Fill){topdot[top][0]=x1;topdot[top++][1]=y1;}
else line (cx,cy,x1,y1);/*画直线段*/
cx=x1;
cy=y1;
break;
case 9:
dx4=getbit(&loop,Bit4,bitbuf)&0x0f;
dy4=getbit(&loop,Bit4,bitbuf)&0x0f;
tmp=dx4&0x07;
tmp=getint(tmp,scalex);
if(dx4&8)x1=cx-tmp;
else x1=cx+tmp;
tmp=dy4&0x07;
tmp=getint(tmp,scaley);
if(dy4&8)y1=cy-tmp;
else y1=cy+tmp;
if(Fill){topdot[top][0]=x1;topdot[top++][1]=y1;}
else line(cx,cy,x1,y1);/*画直线段*/
cx=x1;
cy=y1;
break;
case 10:
dx6=getbit(&loop,Bit6,bitbuf)&0x3f;/*从缓冲区取6位坐标x改变量最高位是符号位*/
dy6=getbit(&loop,Bit6,bitbuf)&0x3f;/* 从缓冲区取6位坐标y改变量最高位是符号位*/
tmp=dx6&0x1f; /*取6位中低5位为x坐标改变量绝对值*/
tmp=getint(tmp,scalex);
if(dx6&0x20)x1=cx-tmp;/*取6位中最高位若为1,则改变量为负*/
else x1=cx+tmp; /*否则为正*/
tmp=dy6&0x1f;
tmp=getint(tmp,scaley);
if(dy6&0x20)y1=cy-tmp;
else y1=cy+tmp;
if(Fill){topdot[top][0]=x1;topdot[top++][1]=y1;} /*若填充存顶点数组*/
else line(cx,cy,x1,y1);/*画直线段*/
cx=x1;
cy=y1;
break;
case 11:
x1=getbit(&loop,Bit4,bitbuf)&0x0f;
y1=getbit(&loop,Bit4,bitbuf)&0x0f;
x2=getbit(&loop,Bit4,bitbuf)&0x0f;
y2=getbit(&loop,Bit4,bitbuf)&0x0f;
tmp=x1&0x07;
tmp=getint(tmp,scalex);
if(x1&8)x1=cx-tmp;
else x1=cx+tmp;
tmp=y1&0x07;
tmp=getint(tmp,scaley);
if(y1&8)y1=cy-tmp;
else y1=cy+tmp;
tmp=x2&0x07;
tmp=getint(tmp,scalex);
if(x2&8)x2=x1-tmp;
else x2=x1+tmp;
tmp=y2&0x07;
tmp=getint(tmp,scaley);
if(y2&8)y2=y1-tmp;
else y2=y1+tmp;
xx[0]=cx;yy[0]=cy;
xx[1]=x1;yy[1]=y1;
xx[2]=x2;yy[2]=y2;
bezier_3(xx,yy);/*三点画二次贝塞尔曲线*/
cx=x2;
cy=y2;
break;
case 12:
x1=getbit(&loop,Bit6,bitbuf)&0x3f;
y1=getbit(&loop,Bit6,bitbuf)&0x3f;
x2=getbit(&loop,Bit6,bitbuf)&0x3f;
y2=getbit(&loop,Bit6,bitbuf)&0x3f;
tmp=x1&0x1f; tmp=getint(tmp,scalex);
if(x1&0x20)x1=cx-tmp;
else x1=cx+tmp;
tmp=y1&0x1f; tmp=getint(tmp,scaley);
if(y1&0x20)y1=cy-tmp;
else y1=cy+tmp;
tmp=x2&0x1f; tmp=getint(tmp,scalex);
if(x2&0x20) x2=x1-tmp;
else x2=x1+tmp;
tmp=y2&0x1f; tmp=getint(tmp,scaley);
if(y2&0x20) y2=y1-tmp;
else y2=y1+tmp;
xx[0]=cx;yy[0]=cy;
xx[1]=x1;yy[1]=y1;
xx[2]=x2;yy[2]=y2;
bezier_3(xx,yy);/*画二次贝塞尔曲线*/
cx=x2;cy=y2;
break;
case 13:
x1=getbit(&loop,Bit4,bitbuf)&0x0f;
y1=getbit(&loop,Bit4,bitbuf)&0x0f;
x2=getbit(&loop,Bit4,bitbuf)&0x0f;
y2=getbit(&loop,Bit4,bitbuf)&0x0f;
x3=getbit(&loop,Bit4,bitbuf)&0x0f;
y3=getbit(&loop,Bit4,bitbuf)&0x0f;
tmp=x1&0x07; tmp=getint(tmp,scalex);
if(x1&8)x1=cx-tmp;
else x1=cx+tmp;
tmp=y1&0x07; tmp=getint(tmp,scaley);
if(y1&8)y1=cy-tmp;
else y1=cy+tmp;
tmp=x2&0x07; tmp=getint(tmp,scalex);
if(x2&8) x2=x1-tmp;
else x2=x1+tmp;
tmp=y2&0x07; tmp=getint(tmp,scaley);
if(y2&8)y2=y1-tmp;
else y2=y1+tmp;
tmp=x3&0x07; tmp=getint(tmp,scalex);
if(x3&8)x3=x2-tmp;
else x3=x2+tmp;
tmp=y3&0x07; tmp=getint(tmp,scaley);
if(y3&8)y3=y2-tmp;
else y3=y2+tmp;
xx[0]=cx;yy[0]=cy;
xx[1]=x1;yy[1]=y1;
xx[2]=x2;yy[2]=y2;
xx[3]=x3;yy[3]=y3;
bezier_4(xx,yy);/*四个顶点画三次贝塞尔曲线*/
cx=x3;cy=y3;
break;
case 14:
x1=getbit(&loop,Bit6,bitbuf)&0x3f;
y1=getbit(&loop,Bit6,bitbuf)&0x3f;
x2=getbit(&loop,Bit6,bitbuf)&0x3f;
y2=getbit(&loop,Bit6,bitbuf)&0x3f;
x3=getbit(&loop,Bit6,bitbuf)&0x3f;
y3=getbit(&loop,Bit6,bitbuf)&0x3f;
tmp=x1&0x1f; tmp=getint(tmp,scalex);
if(x1&0x20)x1=cx-tmp;
else x1=cx+tmp;
tmp=y1&0x1f; tmp=getint(tmp,scaley);
if(y1&0x20)y1=cy-tmp;
else y1=cy+tmp;
tmp=x2&0x1f; tmp=getint(tmp,scalex);
if(x2&0x20) x2=x1-tmp;
else x2=x1+tmp;
tmp=y2&0x1f; tmp=getint(tmp,scaley);
if(y2&0x20)y2=y1-tmp;
else y2=y1+tmp;
tmp=x3&0x1f; tmp=getint(tmp,scalex);
if(x3&0x20)x3=x2-tmp;
else x3=x2+tmp;
tmp=y3&0x1f; tmp=getint(tmp,scaley);
if(y3&0x20)y3=y2-tmp;
else y3=y2+tmp;
xx[0]=cx;yy[0]=cy;
xx[1]=x1;yy[1]=y1;
xx[2]=x2;yy[2]=y2;
xx[3]=x3;yy[3]=y3;
bezier_4(xx,yy);/*四点画三次贝塞尔曲线*/
cx=x3;cy=y3;
break;
case 15:
x1=getbit(&loop,Bit8,bitbuf);/*从缓冲取8位x坐标*/
y1=getbit(&loop,Bit8,bitbuf);/*从缓冲取8位y坐标*/
/*控制字为15不做任何操作*/
break;
}
} /* end while(loop<8*z1)*/
if(Fill&&loop>=8*z1)
{
setcolor(15);
if(getpixel(topdot[0][0],topdot[0][1])==12)
setfillstyle(1,0);/*多边形内孤岛实填充黑色*/
else
setfillstyle(1,12);/*多边形内实填充红色*/
fillpoly(top-1,(int far*)topdot);/*当填充为真,画该汉字最后一个封闭多边形并填充*/
top=0;/*多边形顶点数重归0*/
}
free(dotbuf);
free(bitbuf);
getch();cleardevice();
}/*end while(*hzstr)*/
}
/***************************************/
void bezier_3(int *x,int *y)
{
int *bx,*by;
int i,n=20; /*用20条直线段拟合曲线*/
double a0,a1,a2,dt,xx,t1,t2;
bx=(int *)malloc(n*sizeof(int));
by=(int *)malloc(n*sizeof(int));
if(!bx||!by)
{ printf("memory error!\n");
exit(0);
}
dt=(double)1/(double)n;
a2=x[0]-2*x[1]+x[2];
a1=-2*x[0]+2*x[1];
a0=x[0];
bx[0]=x[0];
for(i=1;i<n;i++)
{
t1=i*dt;
t2=t1*t1;
bx[i]=a0+a1*t1+a2*t2;
}
a2=y[0]-2*y[1]+y[2];
a1=-2*y[0]+2*y[1];
a0=y[0];
by[0]=y[0];
for(i=1;i<n;i++)
{
t1=i*dt;
t2=t1*t1;
by[i]=a0+a1*t1+a2*t2;
}
if(Fill) 诸线段末端坐标存多边形顶点数组
{
topdot[top][0]=bx[0];
topdot[top++][1]=by[0];
for(i=1;i<n;i++)
if((bx[i]!=bx[i-1])||(by[i]!=by[i-1]))
{ topdot[top][0]=bx[i];
topdot[top++][1]=by[i];
}
topdot[top][0]=x[2];
topdot[top++][1]=y[2];
}
else
{ moveto(bx[0],by[0]);
for(i=1;i<n;i++)
if((bx[i]!=bx[i-1])||(by[i]!=by[i-1]))
lineto(bx[i],by[i]);/*画直线段*/
lineto(x[2],y[2]); /*画直线段*/
}
free(bx);
free(by);
}
/***********************************/
void bezier_4(int *x,int *y)
{
int i,*bx,*by;
int n=20;/*用20条直线段拟合曲线*/
double a0,a1,a2,a3,dt,xx,t1,t2,t3;
bx=(int *)malloc(n*sizeof(int));
by=(int *)malloc(n*sizeof(int));
if(!bx||!by)
{
printf("memory error!\n");
getch();
exit(0);
}
dt=(double)1/(double)n;
a3=-x[0]+3*x[1]-3*x[2]+x[3];
a2=3*(x[0]-2*x[1]+x[2]);
a1=3*(x[1]-x[0]);
a0=x[0];
bx[0]=x[0];
for(i=1;i<n;i++)
{ t1=i*dt;
t2=t1*t1;
t3=t1*t2;
bx[i]=a0+a1*t1+a2*t2+a3*t3;
}
a3=-y[0]+3*y[1]-3*y[2]+y[3];
a2=3*(y[0]-2*y[1]+y[2]);
a1=3*(y[1]-y[0]);
a0=y[0];
by[0]=y[0];
for(i=1;i<n;i++)
{
t1=i*dt;
t2=t1*t1;
t3=t1*t2;
by[i]=a0+a1*t1+a2*t2+a3*t3;
}
if(Fill) /*诸线段末端坐标存多边形顶点数组,以便填充*/
{
topdot[top][0]=bx[0];
topdot[top++][1]=by[0];
for(i=1;i<n;i++)
if((bx[i]!=bx[i-1])||(by[i]!=by[i-1]))
{ topdot[top][0]=bx[i];
topdot[top++][1]=by[i];
}
topdot[top][0]=x[3];
topdot[top++][1]=y[3];
}
else
{
moveto(bx[0],by[0]);/*移动画笔*/
for(i=1;i<n;i++)
if((bx[i]!=bx[i-1])||(by[i]!=by[i-1]))
lineto(bx[i],by[i]);/*画直线段*/
lineto(x[3],y[3]);/*画直线段*/
}
free(bx);
free(by);
}
/***************************************/
UC getbit(UI *n,UI b,UC *bitbuf) /*计算4位或6位或8位二进制组成的数*/
{
UC tmp=0;
int i;
for(i=1;i<=b;i++)
tmp+=(bitbuf[(*n)++]<<(b-i));
return(tmp);
}
/***************************************/
UI getint(int num,double scl) /*四舍五入到整数*/
{
double tmp;
tmp=num*scl;
return((fmod(tmp,1)>=0.5)?(int)(tmp+1):(int)tmp);
}
/**********************************************/
void hz16(UC *hzstr,int x,int y,int color)
{
UI QM,WM;
register int i,j,k;
long int pointer,record;
UC hz16buf[32],d=0; /*16点阵单个汉字缓冲区为32字节,d为字间距*/
UC *hzp=hzstr;
FILE *fp;
fp=fopen("hzk16","rb"); /*打开16点阵汉字库文件*/
if(fp==NULL)
{ printf("open hz file fail!\n");
getch();
exit(0);
}
rewind(fp);
while(*hzp) /*显示串中所有字符*/
{
if(*hzp>=160) /*汉字*/
{
QM=(*hzp-0xa1)&0x07f;/*区号*/
WM=(*(hzp+1)-0xa1)&0x7f;/*位号*/
record=(QM)*94+WM;/*字模信息在字库中记录号*/
pointer=record*32L;/*16点阵字模偏移*/
fseek(fp,pointer,SEEK_SET);
fread(hz16buf,32L,1,fp);/*从文件读字模信息到缓冲区*/
for(i=0;i<16;i++) /*16行*/
for(j=0;j<2;j++)/*每行2字节*/
for(k=0;k<8;k++) /*每字节8位二进制*/
if(hz16buf[2*i+j]>>(7-k)&1) /*若该位非空白*/
putpixel(x+j*8+k,y+i,color);/*画点*/
x+=d;/*横坐标增加字间距,以显示下一个汉字*/
hzp+=2;/*下一汉字指针*/
}
else /*若字符为西文*/
{ UC tmp[2]={0};
tmp[0]=*hzp++;
asc16(tmp,x,y,11);/*按西文字库显示*/
}
if(*(hzp-2)>=160)x+=16 /*汉字2字节宽*/;
else x+=8; /*西文1字节宽*/
}
fclose(fp);/*显示完毕后关闭字库文件*/
}
/***************************************************/
void hz24k(UC *hzstr,int x,int y,int color )
{
UI QM,WM;
register int i,j,k;
long int pointer,record;
UC hz24buf[72],d=0,c[2]={'\0'};/*24点阵汉字缓冲区长72字节*/
UC *hzp=hzstr;
FILE *fp;
fp=fopen("hzk24k","rb");/*打开字库文件*/
if(fp==NULL)
{
printf("open hz file fail!\n");
getch();
return;
}
rewind(fp);
while(*hzp)/*显示串中所有字符*/
{
if(*hzp>=160)/*汉字*/
{
QM=(*hzp-0xa1)&0x07f;/*区号*/
WM=(*(hzp+1)-0xa1)&0x7f;/*位号*/
record=(QM-15)*94+WM;/*记录号*/
pointer=record*72L;/*偏移*/
fseek(fp,pointer,SEEK_SET);
fread(hz24buf,72L,1,fp);/*读字模信息*/
for(i=0;i<24;i++)/*24行*/
for(j=0;j<3;j++)/*每行3字节*/
for(k=0;k<8;k++)/*每字节8位*/
if((hz24buf[3*i+j]>>(7-k))&1)/*若该位非0*/
putpixel(x+i,y+j*8+k,color);/*画点*/
x+=d+24;/*下一汉字横坐标*/
hzp+=2;/*下一汉字指针*/
}
else /*若为西文*/
{
c[0]=*hzp;
settextstyle(DEFAULT_FONT,HORIZ_DIR,3);/*用TC默认字库,水平方向,3倍粗*/
outtextxy(x+1,y+2,c);hzp++;x+=d+24;/*输出西文字符*/
}
}
fclose(fp);/*关闭字库文件*/
}
/***************************************************/
void hz48s(UC *hzstr,int x,int y,int color )
{
UI QM,WM;
register int i,j,k;
long int pointer,record;
UC hz48buf[288],d=0,c[2]={'\0'};/*48点阵单个汉字缓冲长为288字节*/
UC *hzp=hzstr;
FILE *fp;
fp=fopen("hzk48s","rb");/*打开48点阵汉字库文件*/
if(fp==NULL)
{
printf("open hz file fail!\n");
getch();
exit(0);
}
rewind(fp);
while(*hzp)/*显示串中所有字符*/
{
if(*hzp>=160)/*汉字*/
{
QM=(*hzp-0xa1)&0x07f;/*区码*/
WM=(*(hzp+1)-0xa1)&0x7f;/*位码*/
record=(QM-15)*94+WM;/*记录号*/
pointer=record*288L;/*字模偏移*/
fseek(fp,pointer,SEEK_SET);
fread(hz48buf,288L,1,fp);/*读单字模信息到缓冲*/
for(i=0;i<48;i++)/*48条扫描线*/
for(j=0;j<6;j++)/*每行6字节*/
for(k=0;k<8;k++)/*每字节8位*/
if(hz48buf[6*i+j]>>(7-k)&1)/*若该位非空*/
putpixel(x+3+j*8+k,y+i,color);/*画点*/
x+=d+48;/*下一汉字横坐标*/
hzp+=2;/*下一汉字指针*/
}
else /*西文*/
{
c[0]=*hzp;
settextstyle(DEFAULT_FONT,HORIZ_DIR,6) /*用TC默认字体6倍粗*/;
outtextxy(x,y+2,c);hzp++;x+=d+48; /*输出该西文字符*/
}
}
fclose(fp);/*关闭西文字库文件*/
}
/***************************************************/
void asc16(UC *asc,int x,int y,int color)/*显示单个西文字符*/
{
register int i,j,k;
long int pointer,record;
UC asc16buf[16],d=0;/*16点阵西文单字缓冲区长为16字节*/
FILE *fp;
fp=fopen("asc16","rb");/*打开西文字库*/
if(fp==NULL)
{
printf("open asc file fail!\n");
getch();
exit(0);
}
rewind(fp);
while(*asc)
{
record=*asc++;/*西文记录号*/
pointer=record*16L;/*偏移*。
fseek(fp,pointer,SEEK_SET);
fread(asc16buf,16L,1,fp);/*读字模信息到缓冲*/
for(i=0;i<16;i++)/*16行*/
for(k=0;k<8;k++)/*每行8位*/
if(asc16buf[i]>>(7-k)&1)/*若该位非空*/
putpixel(x+k+d,y+i,color);/*画点*/
x+=10;/*下一字符横坐标*/
}
fclose(fp);/*关闭字库文件*/
}