TC2.0显示汉字的例子
我们已经知道如何根据汉字库文件,在图形模式下显示汉字,但这里,类似我以前的做法,我提供一个简单的头文件。使它使用起来更方便一些。需要注意的是不同字库主要要注意两点差别:(1)文件中第一个字的起始编码不同,即文件定位方式会有差别,(2)不同字库的扫描序不同,例如12*12和16*16属于按行扫描,而24*24属于按列扫描,这导致输出汉字的代码有差别。(具体的细节不详述了)显示汉字部分的代码参考了(1)《C高级实用程序设计》(王士元)(清华大学出版社),(2)《C高级编程技术.pdf》,以及(3)《信电系C语言大型作业参考资料.doc》(浙江大学,韩 雁,霍明旭,1999年5月)。GetBit和PutChn12的代码主要借鉴和选用了资料(3)中提供的代码,即该部分代码非我的原创。
头文件TEXTOUT.H如下:我们可以把它放到TC的INCLUDE文件夹,这样就像使用其他头文件一样方便了。如果不这样,需要include的时候同时写出它所在的路径。
[code/************************************************************/
/* Desc: 用于TC下的VGA模式下输出汉字字符串 */
/* By: hoodlum1980 */
/* Email: jinfd@ */
/* QQ: 17777538 */
/* Date: 2008-09-11 */
/* Blog: http:// */
/************************************************************/
#ifndef __TEXTOUT_H_INCLUDED
#define __TEXTOUT_H_INCLUDED
#include <graphics.h>
#include <stdio.h>
/*HZK12的全路径*/
char PATH_HZK12[256];
char PATH_HZK16[256];
char PATH_HZK24[256];
/*函数列表*/
char* GetFontPath(int size, int *byteslength);
void SetFontPath(int size, char *filename);
int GetBit(unsigned char byte,int bit);
int GetBitByPos(int size, unsigned char *bytes, int x, int y);
void PutChn(int size, int left, int top, unsigned char *bytes, int color);
void PutChnWithBorder(int size, int left, int top, unsigned char *bytes, int fillcolor, int bordercolor);
int TextOut12(char *string , int x, int y);
int TextOut16(char *string , int x, int y);
int TextOut24(char *string , int x, int y);
int TextOut(char *string, int size, int x, int y, int gap, int fillcolor, int bordercolor);
/*根据size获取路径字符串的地址, 并返回字模字节数组大小 */
char* GetFontPath(int size, int *byteslength)
{
/* byteslength = (size+7)/8*size; */
if(size < (12+16)/2)
{
if(byteslength!=NULL) *byteslength = 24;
return PATH_HZK12;
}
else if(size < (16+24)/2)
{
if(byteslength!=NULL) *byteslength = 32;
return PATH_HZK16;
}
else
{
if(byteslength!=NULL) *byteslength = 72;
return PATH_HZK24;
}
}
/*设置12*12汉字库的文件路径!*/
void SetFontPath(int size, char *filename)
{
strcpy(GetFontPath(size, NULL), filename);
}
/*获取一个字节中的某个位(bit)*/
int GetBit(unsigned char byte,int bit)
{
if(bit<0 || bit>7)
return 0;
return (byte>>bit)& 0x1;
}
/*给出一个字模的大小,字模字节数组,点在字模中的坐标,返回字模中该点的值(0或者1)*/
/*size: 汉字尺寸 = 12,16,24,...*/
int GetBitByPos(int size, unsigned char *bytes, int x, int y)
{
int index, bit;
if(x<0 || x>size-1 || y<0 || y>size-1)
return 0;
/*如果是按行扫描的*/
if(size<=16)
{
index = (size+7)/8 * y + x/8; /*数组索引,位于哪一个byte*/
bit= 7 - (x%8); /*位于该byte的第几位*/
}
else
{
/*按列扫描*/
index = (size+7)/8 *x + y/8;
bit= 7 - (y%8);
}
return GetBit(bytes[index], bit);
}
/*通用的绘制方法,传入字的大小,左上角坐标,字模,颜色*/
void PutChn(int size, int left, int top, unsigned char *bytes, int color)
{
int i,j;
for(i=0;i<size;i++)
for(j=0;j<size;j++)
if(GetBitByPos(size, bytes, i, j))
putpixel(left+i, top+j, color);
}
/*绘制汉字,并且绘制汉字边缘!*/
void PutChnWithBorder(int size, int left, int top, unsigned char *bytes, int fillcolor, int bordercolor)
{
int i,j,k;
char pos[8][2]={-1,-1, 0,-1, 1,-1, -1,0, 1,0, -1,1, 0,1, 1,1};
for(i=0;i<size;i++)
{
for(j=0;j<size;j++)
{
if(GetBitByPos(size, bytes, i,j))
{
/*绘制像素点*/
if(fillcolor>=0)
putpixel(left+i, top+j, fillcolor);
/*绘制边缘*/
for(k=0;k<8;k++)
{
if(!GetBitByPos(size, bytes, i+pos[k][0], j+pos[k][1]))
putpixel(left+i+pos[k][0], top+j+pos[k][1], bordercolor);
}
}
}
}
}
/*给出一个汉字的12_12字模入口地址,在指定位置输出这个汉字 */
/*bytes是汉字的字模字节数组,12_12像素字库是按行扫描的。*/
/*
void PutChn12(int x, int y, unsigned char* bytes, int color)
{
int i, j, bit;
for(i=0; i<12; i++)
for(j=0; j<2; j++)
for(bit=0; bit<8 && (j*8+bit)<12; bit++)
if( GetBit(bytes[i*2+j], 7-bit) )
putpixel( x + j*8 + bit, y + i, color);
}
*/
/*默认的绘制12*12字符串*/
int TextOut12(char *string , int x, int y)
{
return TextOut(string, 12, x, y, 2, getcolor(), -1);
}
/*默认的绘制16*16字符串*/
int TextOut16(char *string , int x, int y)
{
return TextOut(string, 16, x, y, 2, getcolor(), -1);
}
/*默认的绘制24*24字符串*/
int TextOut24(char *string , int x, int y)
{
return TextOut(string, 24, x, y, 2, getcolor(), -1);
}
/*在指定位置输出一行中文字符串, string必须是汉字组成的字符串*/
/*x,y:字符串的左上角位置。color:颜色。gap:相邻汉字之间的像素间距*/
/*返回输出的字符数量*/
int TextOut(char *string, int size, int x, int y, int gap, int fillcolor, int bordercolor)
{
unsigned char qh, wh, qhbase, *pChar; /*区号,位号, 起始区号*/
unsigned long offset; /*文件偏移地址*/
unsigned char *bytes[72]; /*当前字模字节数组*/
char text[2]={0x00,0x00}; /*这是为了输出英文字符*/
char pos[8][2]={-1,-1, 0,-1, 1,-1, -1,0, 1,0, -1,1, 0,1, 1,1};
int i,originColor, left=x, count=0, k, byteslength; /*left是当前字的X坐标, count是字符数量计数*/
FILE *stream;
qhbase=(size<=16)? 0:15; /*起始区号*/
stream=fopen(GetFontPath(size, &byteslength), "rb");
if(stream==NULL)
return 0;
/*把char[]当作无符号字符*/
pChar=(unsigned char*)string;
/*保存现有的颜色*/
originColor=getcolor();
/*依次输出每个汉字*/
for(i=0; i<strlen(string); i++, count++)
{
/*判断是字符是否是英文字符*/
if(pChar[i] < 0xa1)
{
/*输出英文字符*/
text[0]=pChar[i];
if(bordercolor>=0)
{
setcolor(bordercolor);
for(k=0;k<8;k++)
outtextxy(left+pos[k][0], y+size/2-3+pos[k][1], text);
}
setcolor(fillcolor>=0? fillcolor: getbkcolor());
outtextxy(left, y+size/2-3, text); /*默认字体比较扁些*/
left += (6+gap);
}
else
{
/*输出汉字字符*/
qh=(pChar[i ]-0xa1)&0x07F; /*得到区号*/
wh=(pChar[i+1]-0xa1)&0x07F; /*得到位号*/
offset = (94*(qh-qhbase)+wh)*((unsigned long)byteslength); /*得到偏移位置,对于12字库,每个汉字24个字节*/
fseek(stream, offset, SEEK_SET); /*移文件指针到要读取的汉字字模处*/
fread(bytes, byteslength, 1, stream); /*读取24 bytes的汉字字模*/
/*输出这个汉字*/
if(bordercolor<0)
PutChn(size,left,y,bytes,fillcolor);
else
PutChnWithBorder(size, left, y, bytes, fillcolor, bordercolor);/*输出这个汉字*/
left += (size+gap);
i++;/*因为每个汉字占用2个字节,因此跳过下一个字节*/
}
}
setcolor(originColor);/*复原前景色*/
fclose(stream);
return count; /*返回输出字符数*/
}
#endif /* END OF ifndef __TEXTOUT_H_INCLUDED */[/code]
下面的代码示范了如何使用这个头文件。
#include <textout.h>
#include <dir.h>
void main()
{
int gdriver=DETECT,gmode;
char filename[256];
char string[]="Hello_这是一个如何使用的例子__by_hoodlum";
/*设置汉字库文件的路径*/
getcwd(filename, sizeof(filename));
strcat(filename, "\\HZK12");
SetFontPath(12, filename);
initgraph(&gdriver, &gmode, "");
TextOut(
string, /*要输出的字符串*/
12, /*字体大小*/
10, 100, /*左上角坐标*/
2, /*字符间距*/
LIGHTGRAY, /*字体颜色*/
-1 /*边缘颜色*/
);
getch();
closegraph();
}
我们做的第一步是指明汉字库文件所在的路径,第二步即可调用TextOut函数输出一个中文字符串。它的参数表示的分别是字符串地址,输出位置左上角的坐标,相邻汉字间距,颜色。当然调用这个函数之前,应该先进入TC的图形模式。
下面是说明文件的内容:
INCLUDE\ TEXTOUT.H
重要函数:
void SetFontPath(int size, char *filename);
设置汉字库的文件路径;size=12,16,或24;
int TextOut(char *string, int size, int x, int y, int gap, int fillcolor, int bordercolor);
输出一个字符串,x,y指定左上角坐标,gap为相邻汉字字符间距,
fillcolor为字体填充颜色,bordercolor为边缘颜色。
TEXTOUTDEMO.C
示范如何使用textout.h的文件。
HZK12
12*12像素的汉字库文件,它是按行扫描的。下图为汉字“啊”的字模数组的存储方式。
##请注意12*12和16*16都是按行扫描的,而24*24是按列扫描的。
[]内数字为字节数组的索引。○为字节中未使用的位。□表示0,■表示1.
------------------------------------------
bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
------------------------------------------
[00] □□■□□□□□□□■□○○○○ [01]
[02] ■■■■■■■■■■■■○○○○ [03]
[04] ■□■□■□■□□□■□○○○○ [05]
[06] ■□■□■■■■■□■□○○○○ [07]
[08] ■□■□■□■□■□■□○○○○ [09]
[10] ■□■□■■■□■□■□○○○○ [11]
[12] ■□■□■□■□■□■□○○○○ [13]
[14] ■■■□■□■■■□■□○○○○ [15]
[16] ■□■□■■□□□□■□○○○○ [17]
[18] □□□□■□□□□□■□○○○○ [19]
[20] □□□□■□□□■□■□○○○○ [21]
[22] □□□□■□□□□■■□○○○○ [23]
------------------------------------------
unsigned char bytes[24]=
{
0x20, 0x20, 0xFF, 0xF0, 0xAA, 0x20,
0xAF, 0xA0, 0xAA, 0xA0, 0xAE, 0xA0,
0xAA, 0xA0, 0xEB, 0xA0, 0xAC, 0x20,
0x08, 0x20, 0x08, 0xA0, 0x08, 0x60
};
附件中是代码,可执行文件和12*12像素的汉字库文件。截图效果省略了。
[[it] 本帖最后由 hoodlum1980 于 2008-10-7 20:41 编辑 [/it]]