根据DOS汉字字库在图形模式下绘制汉字
本文的绘制汉字部分的代码,主要取材于清华大学出版社出版的《C高级实用程序设计》(王士元著),基本上没有什么改动。其中的DOS汉字库由于太古董了,当我想尝试这部分代码时,在网络上找不到这种字库文件。在搜索时无意来到了这个论坛。现在我将在TC的图形模式下绘制汉字部分的代码再贴出来,并且也把我收集到了几个DOS汉字库作为附件。请注意的是,字库文件有16*16像素,24*24像素,当然还有更大分辨率的字库,不过我这里收集到的只有这两种大小。要注意的是:字库文件由于其中起始分区不同,字模大小不同,所以文件的定位方法也不同。同时,由于字模的扫描序不同,分为按行扫描(16*16)和按列扫描(24*24),所以根据字模绘制时的代码也不同。有关文件定位以字模扫描序的细节可以参考我技术博客上的这篇文章(这里不再细述):
http://
附件中的文件是:
HZK24F:仿宋,24*24像素。
HZK24H:黑体,24*24像素。
HZK24S:宋体,24*24像素。
HZK16: 宋体,16*16像素。
我把所有字库文件放到了TC的FONTS目录下,在下面的代码中必须把文件地址设置为有效的字库文件路径。
代码如下:(其中的CPYSCR.H是我此前一篇文章中提到的TC图形模式下的用于截屏的代码,这里我把它注掉了。)
程序代码:
/* * 根据汉字字库的字形,在图形模式下绘制汉字。 */ #include <stdio.h> #include <graphics.h> /* #include <CPYSCR.h> */ /* 用于TC图形模式下的“截屏”,其内容参加我的另一篇文章。 */ void get_hz24(FILE *stream,char incode[],char bytes[]); /* 读取字模到缓冲区 */ void get_hz16(FILE *stream,char incode[],char bytes[]); void dishz24(FILE *stream,int x,int y,char cade[],int color); /* 根据字模绘制汉字 */ void dishz16(FILE *stream,int x,int y,char cade[],int color); void test24(FILE *stream); /* 测试函数,用于输出一部分24*24字库内容(输出汉字的长宽被放大为2倍,即48*48) */ void test16(FILE *stream); /* 测试函数,用于输出一部分16*16字库内容 */ /* 根据汉字库文件绘制文字 */ main() { int x=0,y=0,driver=DETECT, mode=0; /* HZK24H--黑体, HZK24F--仿宋, HZK24S--宋体 */ char *filename24="c:\\tc\\fonts\\HZK24S"; /* 这里是24*24的字库文件的路径!*/ char *filename16="c:\\tc\\fonts\\HZK16"; /* 这里是16*16的字库文件的路径!*/ FILE *hzk_p24,*hzk_p16; char *s="朝辞白帝彩云间千里江陵一日还两岸猿声啼不住轻舟已过万重山"; initgraph(&driver,&mode,""); hzk_p24=fopen(filename24,"rb"); hzk_p16=fopen(filename16,"rb"); if(hzk_p24==NULL || hzk_p16==NULL) { printf("failed to open file!\n"); return; } test16(hzk_p16); /* 测试,显示16字库的前部分内容。 */ /* CopyScreen("c:\\tc\\TEMP\\scr_3.bmp",0,0,600,480); */ getch(); cleardevice(); while (*s!=NULL) { while (x<=324 && *s) { dishz24(hzk_p24,x,y,s,YELLOW); dishz16(hzk_p16,x+4,y+60,s,CYAN); x+=24; s+=2; } x=0, y+=24; /*显示的汉字是24*24像素或者16*16像素*/ } /* CopyScreen("c:\\tc\\TEMP\\scr_4.bmp",0,0,600,480); */ /* 截屏 */ fclose(hzk_p24); fclose(hzk_p16); getch(); closegraph(); } /*输出前几个汉字*/ void test24(FILE *stream) { unsigned char mask[]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}; char mat[72]; unsigned long offset=(0*94+00)*72L;/*汉子码:5101*/ int i,j,k,m,x=10,y=160; for(m=0;m<16;m++) { fseek(stream,offset,SEEK_SET); /*移文件指针到要读取的汉字字模处*/ fread(mat,72,1,stream); /*读取汉字字模*/ for (i=0;i<24*2;i+=2) { for(j=0;j<3*2;j+=2) { for(k=0;k<8*2;k+=2) { /*屏蔽出汉字字模的一个位,即一个点是1 则显示,否则不显示该点*/ if (mask[(k/2)%8] & mat[(3*i+j)/2]) { putpixel(x+i,y+j*8+k,LIGHTBLUE); putpixel(x+i,y+j*8+k+1,LIGHTBLUE); putpixel(x+i+1,y+j*8+k,LIGHTBLUE); putpixel(x+i+1,y+j*8+k+1,LIGHTBLUE); } } } } x+=24*2; offset+=72; } } /* 读取24字库的字模,注意24字库文件直接从汉字区开始 */ void get_hz24(FILE* stream,char incode[],char bytes[]) { unsigned char qh,wh; unsigned long offset; qh=(incode[0]-15-0xa1)&0x07F; /*得到区号*/ wh=(incode[1]-0xa1)&0x07F; /*得到位号*/ offset=(94*qh+wh)*72L; /*24*24的偏移位置*/ fseek(stream,offset,SEEK_SET); /*移文件指针到要读取的汉字字模处*/ fread(bytes,72,1,stream); /*读取72 bytes的汉字字模*/ } /* 绘制24*24像素汉字 */ void dishz24(FILE *stream,int x0,int y0,char code[],int color) { /*屏蔽字模每行各位的数组*/ unsigned char mask[]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}; int i,j,k; char mat[72]; get_hz24(stream,code,mat); /*把读到的字节填充到Mat数组*/ for (i=0;i<24;++i) { for(j=0;j<3;++j) { for(k=0;k<8;k++) { /*屏蔽出汉字字模的一个位,即一个点是1 则显示,否则不显示该点*/ if (mask[k%8] & mat[3*i+j]) putpixel(x0+i,y0+j*8+k,color); } } } } /*获取16*16的字模,注意16和24字库的文件定位方式不同!,16字库前面含有15个区的特殊符号字符*/ void get_hz16(FILE *stream, char incode[],char bytes[]) { unsigned char qh,wh; unsigned long offset; qh=incode[0]-0xa1; /*得到区号*/ wh=incode[1]-0xa1; /*得到位号*/ offset=(94*qh+wh)*32L; /*得到偏移位置*/ fseek(stream,offset,SEEK_SET); /*移文件指针到要读取的汉字字模处*/ fread(bytes,32,1,stream); /*读取32 bytes的汉字字模*/ } /* display a charater in 16*16 pixels, scaned by line */ void dishz16(FILE *stream,int x0,int y0,char code[],int color) { unsigned char mask[]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}; /*屏蔽字模每行各位的数组*/ int i,j,x,y,pos; char mat[32]; get_hz16(stream,code,mat); y=y0; for (i=0;i<16;++i) { x=x0; pos=2*i; for(j=0;j<16;++j) { /*屏蔽出汉字字模的一个位,即一个点是1 则显示,否则不显示该点*/ if (mask[j%8] & mat[pos+j/8]) putpixel(x,y,color); ++x; } ++y; } } /*输出前几个汉字*/ void test16(FILE *stream) { unsigned char mask[]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}; char mat[32]; int lines=25,start=1,items=32; /* start: start line */ unsigned long offset;/*汉子码:5101*/ int i,j,k,m,x=10,y=12; offset = items*lines*start*32L; printf(" 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F"); for(m=0;m<items*lines;m++) { fseek(stream,offset,SEEK_SET); /*移文件指针到要读取的汉字字模处*/ fread(mat,32,1,stream); /*读取32 bytes字模*/ for (i=0;i<16;i++) { for(j=0;j<16;j++) { /*屏蔽出汉字字模的一个位,即一个点是1 则显示,否则不显示该点*/ if (mask[i%8] & mat[j*2+i/8]) putpixel(x+i,y+j,LIGHTBLUE); } } putpixel(x,y,LIGHTYELLOW); /* 我在每个字符的左上角标记一个小点。 */ x+=16; offset+=32; if((m+1)%items==0) /* 这里进行换行。 */ { x=10; y+=16; } } }
在上面的代码中有两个测试函数,分别是test16(),test24(),需要提供相应的文件指针作为参数,这两个函数是我写的用于绘制字库的前面一部分字符的测试代码。使用test16函数可以看到HZK16前面非汉字区的特殊字符内容。使用test24函数可以看到24*24字库的前面一部分汉字。
字库文件的下载地址(代码中需要指定这些字库文件的路径):
http://汉字字库文件.rar
下面是效果截图(当然,截图效果看起来就像是用Windows下的软件绘制的图像):
[[it] 本帖最后由 hoodlum1980 于 2008-3-16 16:38 编辑 [/it]]