字模提取原理
- 格式:doc
- 大小:39.50 KB
- 文档页数:8
5.7点阵字模生成原理与方法[3]5.7.1 字模生成原理本设计中因为使用汉字的点阵显示,需要提取汉字字模,因此我们首先来了解汉字点阵字模的提取方法。
汉字的点阵字模是从点阵字库文件中提取出来的。
例如常用的16×16点阵HZK16文件,12×12点阵HZK12文件等等,这些文件包括了GB 2312字符集中的所有汉字。
现在只要弄清汉字点阵在字库文件中的格式,就可以按照自己的意愿去显示汉字了。
下面以HZK16文件为例,分析取得汉字点阵字模的方法。
HZK16文件是按照GB 2312-80标准,也就是通常所说的国标码或区位码的标准排列的。
国标码分为 94 个区(Section),每个区 94个位(Position),所以也称为区位码。
其中01~09 区为符号、数字区,16~87 区为汉字区。
而 10~15 区、88~94 区是空白区域。
如何取得汉字的区位码呢?在计算机处理汉字和ASCII字符时,使每个ASCII字符占用1个字节,而一个汉字占用两个字节,其值称为汉字的内码。
其中第一个字节的值为区号加上32(20H),第二个字节的值为位号加上32(20H)。
为了与ASCII字符区别开,表示汉字的两个字节的最高位都是1,也就是两个字节的值都又加上了128(80H)。
这样,通过汉字的内码,就可以计算出汉字的区位码。
具体算式如下:qh=c1-32-128=c1-160 wh=c2-32-128=c2-160或qh=c1-0xa0 wh=c2-0xa0qh,wh为汉字的区号和位号,c1,c2为汉字的第一字节和第二字节。
根据区号和位号可以得到汉字字模在文件中的位置:location=(94*(qh-1)+(wh-1))*一个点阵字模的字节数。
那么一个点阵字模究竟占用多少字节数呢?我们来分析一下汉字字模的具体排列方式。
例如下图中显示的“汉”字,使用16×16点阵。
字模中每一点使用一个二进制位(Bit)表示,如果是1,则说明此处有点,若是0,则说明没有。
这样,一个16×16点阵的汉字总共需要16*16/8=32个字节表示。
字模的表示顺序为:先从左到右,再从上到下,也就是先画左上方的8个点,再是右上方的8个点,然后是第二行左边8个点,右边8个点,依此类推,画满16×16个点。
对于其它点阵字库文件,则也是使用类似的方法进行显示。
例如HZK12,但是HZK12文件的格式有些特别,如果你将它的字模当作12*12位计算的话,根本无法正常显示汉字。
因为字库设计者为了使用的方便,字模每行的位数均补齐为8的整数倍,于是实际该字库的位长度是16*12,每个字模大小为24字节,虽然每行都多出了4位,但这4位都是0(不显示),并不影响显示效果。
还有UCDOS下的HZK24S(宋体)、HZK24K(楷体)或HZK24H(黑体)这些打印字库文件,每个字模占用24*24/8=72字节,不过这类大字模汉字库为了打印的方便,将字模都放倒了,所以在显示时要注意把横纵方向颠倒过来就可以了。
这样我们就完全清楚了如何得到汉字的点阵字模,这样就可以在程序中随意的显示汉字了。
5.7.2 字模提取程序如果在程序中使用的汉字数目不多,也可以不必总是在程序里带上几百K的字库文件,也许你的程序才只有几十K。
这样可以事先将所需要显示的汉字字模提取出来,放在另一个文件里,按照自己的顺序读取文件就可以了。
下面的程序说明了具体显示汉字的方法,以16×16汉字为例,使用HZK16文件。
#include<stdio.h>#include<graphics.h>/* x,y为显示坐标,s为显示字符串,colour为颜色 */void hanzi16(int x,int y,char *s,int colour){FILE *fp;char buffer[32]; /* 32字节的字模缓冲区 */register i,j,k;unsigned char qh,wh;unsigned long location;if((fp=fopen("hzk16","rb"))==NULL){printf("Can't open hzk16!");getch();exit(0);}while(*s){qh=*s-0xa0;wh=*(s+1)-0xa0;location=(94*(qh-1)+(wh-1))*32L; /* 计算汉字字模在文件中的位置 */fseek(fp,location,SEEK_SET);fread(buffer,1,32,fp);for(i=0;i<16;i++)for(j=0;j<2;j++)for(k=0;k<8;k++)if(((buffer[i*2+j]>>(7-k))&0x1)!=NULL)putpixel(x+8*j+k,y+i,colour);s+=2;x+=16; /* 汉字间距 */}fclose(fp);}main(){int gd=DETECT,gm;initgraph(&gd,&gm,"");hanzi16(246,200,"贵州民族学院物电学院二零零三级电子二班杨智斌!",BROWN);getch();closegraph();}在TC 2.0下运行上面程序,就在屏幕上打印出你想要显示的汉字,例如该程序运行后会在屏幕上显示:贵州民族学院物电学院二零零三级电子二班杨智斌!程序中每次将一个汉字的点阵字模存储于buffer[32]缓冲数组里面,因此我们可以编程从该缓冲数据组里面取出对应汉字的点阵模存储于另的一个数组里面,然后可以通过PC机串口发送给单片机,最后显示在LED点阵显示屏上。
由于时间比较紧,这一步我没有做出来,希望有人能够补充完整,在制作过程中我是用了别人已经写好了的点阵字模提取软件来提取点阵字模。
Windows API一日一练(90)GetGlyphOutline函数收藏中西文化的差异,导致在电子信息里处理也大不相同,在英文里只需要26个字母就可以显示所有文章了,而在中文里需要最基本的字符就有2000多个。
对于一些在嵌入式软件里要显示的字符,那么就得手动去构造所有图形,这是一个比较大的工作量,如果让每个厂家都去完成这个任务,显然是不可能的。
面对着大量嵌入式用户的需求,那么就需要解决中文字模的图形问题。
毕竟大家经常使用Windows,最先想到的,肯定是怎么样把里面的字符提取图形出来,生成自己需要的几个字库。
下面就来介绍怎么样用函数GetGlyphOutline获取显示字符的图形数据。
函数GetGlyphOutline声明如下:WINGDIAPI DWORD WINAPI GetGlyphOutlineA( __in HDC hdc,__in UINT uChar,__in UINT fuFormat,__out LPGL YPHMETRICS lpgm,__in DWORD cjBuffer,__out_bcount_opt(cjBuffer) LPVOID pvBuffer,__in CONST MAT2 *lpmat2);WINGDIAPI DWORD WINAPI GetGlyphOutlineW( __in HDC hdc,__in UINT uChar,__in UINT fuFormat,__out LPGL YPHMETRICS lpgm,__in DWORD cjBuffer,__out_bcount_opt(cjBuffer) LPVOID pvBuffer,__in CONST MAT2 *lpmat2);#ifdef UNICODE#define GetGlyphOutline GetGlyphOutlineW#else#define GetGlyphOutline GetGlyphOutlineA#endif // !UNICODEhdc是设备句柄。
uChar是需要获取图形数据的字符。
fuFormat是获取数据的格式。
lpgm是获取字符的相关信息。
cjBuffer是保存字符数据的缓冲区大小。
pvBuffer是保存字符数据的缓冲区。
lpmat2是3*3的变换矩阵。
调用函数的例子如下:#001 //浮点数据转换为固定浮点数。
#002 FIXED FixedFromDouble(double d)#003 {#004 long l;#005 l = (long) (d * 65536L);#006 return *(FIXED *)&l;#007 }#008#009 //设置字体图形变换矩阵。
#010 void SetMat(LPMAT2 lpMat)#011 {#012 lpMat->eM11 = FixedFromDouble(2);#013 lpMat->eM12 = FixedFromDouble(0);#014 lpMat->eM21 = FixedFromDouble(0);#015 lpMat->eM22 = FixedFromDouble(2);#016 }#017#018 //#019 //获取字模信息。
#020 //蔡军生2007/12/16 QQ:9073204 深圳#021 void TestFontGlyph(void)#022 {#023 //创建字体。
#024 HFONT hFont = GetFont();#025#026 //设置字体到当前设备。
#027 HDC hDC = ::GetDC(m_hWnd);#028 HFONT hOldFont = (HFONT)SelectObject(hDC,hFont);#029#030 //设置字体图形变换矩阵#031 MAT2 mat2;#032 SetMat(&mat2);#033#034#035 GL YPHMETRICS gm;#036#037 //设置要显示的字符。
#038 TCHAR chText = L'蔡';#039#040 //获取这个字符图形需要的字节的大小。
#041 DWORD dwNeedSize =GetGlyphOutline(hDC,chText,GGO_BITMAP,&gm,0,NULL,&mat2);#042 if (dwNeedSize > 0 && dwNeedSize < 0xFFFF)#043 {#044 //按需要分配内存。