所有的汉字或者英文都是下面的原理Word格式.docx
- 文档编号:19032544
- 上传时间:2023-01-03
- 格式:DOCX
- 页数:22
- 大小:808.77KB
所有的汉字或者英文都是下面的原理Word格式.docx
《所有的汉字或者英文都是下面的原理Word格式.docx》由会员分享,可在线阅读,更多相关《所有的汉字或者英文都是下面的原理Word格式.docx(22页珍藏版)》请在冰豆网上搜索。
|1||||||1||||||1||||
||1|1||||1||||||1||||
|||1||||1|||||1|||||
|||||1|||1||||1|||||
||||1||||1|||1||||||
|||1||||||1||1||||||
|1|1|1|||||||1|||||||
|||1|||||1||||1|||||
|||1||||1||||||1||||
|||1|||1|||||||1|1|1||
|||||1|||||||||1|||
|||||||||||||||||
可以看出这是一个"
汉"
字的点阵,当然文本的方式效果不是很好.根据上面的原则,我们可以写出这个点阵的点阵数据:
0x40,0x08,0x37,0xfc,0x10,0x08,…,当然写这个确实很麻烦所以我不再继续下去.我这样做,也只是为了向你说明,在点阵字库中,每一个点阵的数据就是按照这种方式存放的.
当然也存在着不规则的点阵,这里说的不规则,指的是点阵的宽度不是8的倍数,比如12*12的点阵,那么这样的点阵数据又是如何存放的呢?
其实也很简单,每一行的前面8个点存放在一个字节里面,每一行的剩下的4点就使用一个字节来存放,也就是说剩下的4个点将占用一个字节的高4位,而这个字节的低4位没有使用,全部都默认的为零.这样做当然显得有点浪费,不过却能够便于我们进行存放和寻址.对于其他不规则的点阵,也是按照这个原则进行处理的.这样我们可以得出一个m*n的点阵所占用的字节数为(m+7)/8*n.
在明白了以上所讲的以后,我们可以写出一个显示一个任意大小的点阵字模的函数,这个函数的功能是输出一个宽度为w,高度为h的字模到屏幕的(x,y)坐标出,文字的颜色为color,文字的点阵数据为pdata所指:
/*输出字模的函数*/
void_draw_model(char*pdata,intw,inth,intx,inty,intcolor)
{
int
i;
/*控制行*/
j;
/*控制一行中的8个点*/
k;
/*一行中的第几个"
8个点"
了*/
nc;
/*到点阵数据的第几个字节了*/
cols;
/*控制列*/
BYTE
staticmask[8]={128,64,32,16,8,4,2,1};
/*位屏蔽字*/
w=(w+7)/8*8;
/*重新计算w*/
nc=0;
for(i=0;
i<
h;
i++)
cols=0;
for(k=0;
k<
w/8;
k++)
for(j=0;
j<
8;
j++)
if(pdata[nc]&
mask[j])
putpixel(x+cols,y+i,color);
cols++;
}
nc++;
代码很简单,不用怎么讲解就能看懂,代码可能不是最优化的,但是应该是最易读懂的.其中的putpixel函数,使用的是TC提供的Graphics中的画点函数.使用这个函数就可以完成点阵任意大小的点阵字模的输出.
接下来的问题就是如何在汉子库中寻址某个汉子的点阵数据了.要解决这个问题,首先需要了解汉字在计算机中是如何表示的.在计算机中英文可以使用ASCII码来表示,而汉字使用的是扩展ASCII码,并且使用两个扩展ASCII码来表示一个汉字.一个ASCII码使用一个字节表示,所谓扩展ASCII码,也就是ASCII码的最高位是1的ASCII码,简单的说就是码值大于等于128的ASCII码.一个汉字由两个扩展ASCII码组成,第一个扩展ASCII码用来存放区码,第二个扩展ASCII码用来存放位码.在GB2312-80标准中,将所有的汉字分为94个区,每个区有94个位可以存放94个汉字,形成了人们常说的区位码,这样总共就有94*94=8836个汉字.在点阵字库中,汉字点阵数据就是按照这个区位的顺序来存放的,也就是最先存放的是第一个区的汉字点阵数据,在每一个区中有是按照位的顺序来存放的.在汉字的内码中,汉字区位码的存放实在扩展ASCII基础上存放的,并且将区码和位码都加上了32,然后存放在两个扩展ASCII码中.具体的说就是:
第一个扩展ASCII码=128+32+汉字区码
第二个扩展ASCII吗=128+32+汉字位码
如果用charhz[2]来表示一个汉字,那么我可以计算出这个汉字的区位码为:
区码=hz[0]-128-32=hz[0]-160
位码=hz[1]-128-32=hz[1]-160.
这样,我们可以根据区位码在文件中进行殉职了,寻址公式如下:
汉字点阵数据在字库文件中的偏移=((区码-1)*94+位码)*一个点阵字模占用的字节数
在寻址以后,即可读取汉字的点阵数据到缓冲区进行显示了.以下是实现代码:
/*输出一个汉字的函数*/
void_draw_hz(charhz[2],FILE*fp,intx,inty,intw,inth,intcolor)
charfONtbuf[128];
/*足够大的缓冲区,也可以动态分配*/
intch0=(BYTE)hz[0]-0xA0;
/*区码*/
intch1=(BYTE)hz[1]-0xA0;
/*位码*/
/*计算偏移*/
longoffset=(long)pf->
_hz_buf_size*((ch0-1)*94+ch1-1);
fseek(fp,offset,SEEK_SET);
/*进行寻址*/
fread(fontbuf,1,(w+7)/8*h,fp);
/*读入点阵数据*/
_draw_model(fontbuf,w,h,x,y,color);
/*绘制字模*/
以上介绍完了中文点阵字库的原理,当然还有英文点阵字库了.英文点阵字库中单个点阵字模数据的存放方式与中文是一模一样的,也就是对我们所写的_draw_model函数同样可以使用到英文字库中.唯一不同的是对点阵字库的寻址上.英文使用的就是ASCII码,其码值是0到127,寻址公式为:
英文点阵数据在英文点阵字库中的偏移=英文的ASCII码*一个英文字模占用的字节数
可以看到,区分中英文的关键就是,一个字符是ASCII码还是扩展ASCII码,如果是ASCII码,其范围是0到127,这样是使用的英文字库,如果是扩展ASCII码,则与其后的另一个扩展ASCII码组成汉字内码,使用中文字库进行显示.只要正确区分ASCII码的类型并进行分别的处理,也就能实现中英文字符串的混合输出了.
点阵字库和矢量字库的差别
我们都只知道,各种字符在电脑屏幕上都是以一些点来表示的,因此也叫点阵.最早的字库就是直接把这些点存储起来,就是点阵字库.常见的汉字点阵字库有16x16,24x24等.点阵字库也有很多种,主要区别在于其中存储编码的方式不同.点阵字库的最大缺点就是它是固定分辨率的,也就是每种字库都有固定的大小尺寸,在原始尺寸下使用,效果很好,但如果将其放大或缩小使用,效果就很糟糕了,就会出现我们通常说的锯齿现象.因为需要的字体大小组合有无数种,我们也不可能为每种大小都定义一个点阵字库.于是就出现了矢量字库.
矢量字库
矢量字库是把每个字符的笔划分解成各种直线和曲线,然后记下这些直线和曲线的参数,在显示的时候,再根据具体的尺寸大小,画出这些线条,就还原了原来的字符.它的好处就是可以随意放大缩小而不失真.而且所需存储量和字符大小无关.矢量字库有很多种,区别在于他们采用的不同数学模型来描述组成字符的线条.常见的矢量字库有Type1字库和Truetype字库.
在点阵字库中,每个字符由一个位图表示(如图2.5所示),并把它用一个称为字符掩膜的矩阵来表示,其中的每个元素都是一位二进制数,如果该位为1表示字符的笔画经过此位,该像素置为字符颜色;
如果该位为0,表示字符的笔画不经过此位,该像素置为背景颜色.点阵字符的显示分为两步:
首先从字库中将它的位图检索出来,然后将检索到的位图写到帧缓冲器中.
在实际应用中,同一个字符有多种字体(如宋体、楷体等),每种字体又有多种大小型号,因此字库的存储空间十分庞大.为了减少存储空间,一般采用压缩技术.
矢量字符记录字符的笔画信息而不是整个位图,具有存储空间小,美观、变换方便等优点.例如:
在AutoCAD中使用图形实体-形(Shape)-来定义矢量字符,其中,采用了直线和圆弧作为基本的笔画来对矢量字符进行描述.对于字符的旋转、放大、缩小等几何变换,点阵字符需要对其位图中的每个象素进行变换,而矢量字符则只需要对其几何图素进行变换就可以了,例如:
对直线笔画的两个端点进行变换,对圆弧的起点、终点、半径和圆心进行变换等等.
矢量字符的显示也分为两步.首先从字库中将它的字符信息.然后取出端点坐标,对其进行适当的几何变换,再根据各端点的标志显示出字符.
轮廓字形法是当今国际上最流行的一种字符表示方法,其压缩比大,且能保证字符质量.轮廓字形法采用直线、B样条/Bezier曲线的集合来描述一个字符的轮廓线.轮廓线构成一个或若干个封闭的平面区域.轮廓线定义加上一些指示横宽、竖宽、基点、基线等等控制信息就构成了字符的压缩数据.
如何使用Windows的系统字库生成点阵字库?
我的程序现在只能预览一个汉字的不同字体的点阵表达.
界面很简单:
一个输出点阵大小的选择列表(8x8,16x16,24x24等),一个系统中已有的字体名称列表,一个预览按钮,一块画图显示区域.
得到字体列表的方法:
(作者称这一段是用来取回系统的字体,然后添加到下拉框中)
//取字体名称列表的回调函数,使用前要声明一下该方法
CALLBACK
MyEnumFONtProc(ENUMLOGFONTEX*
lpelf,NEWTEXTMETRICEX*
lpntm,DWORD
nFontType,long
lParam)
CFontPeekerDlg*
pWnd=(CFontPeekerDlg*)
lParam;
if(pWnd)
if(
pWnd->
m_combo_sfont.FindSTring(0,
lpelf->
elfLogFont.lfFaceName)
<
0
)
m_combo_sfont.AddString(lpelf->
elfLogFont.lfFaceName);
return
1;
0;
//说明:
CFontPeekerDlg
是我的dialog的类名,
m_combo_sfont是列表名称下拉combobox关联的control变量
//调用的地方
(******问题1:
下面那个&
lf怎么得到呢……)
:
:
EnumFontFamiliesEx((HDC)
dc,&
lf,
(FONTENUMPROC)MyEnumFontProc,(LPARAM)
this,0);
m_combo_sfont.SetCurSel(0);
字体预览:
如果点阵大小选择16,显示的时候就画出16x16个方格.自定义一个类CMyStatic继承自CStatic,用来画图.在CMyStatic的OnPaint()函数中计算并显示.
取得字体:
常用的方法:
用CreateFont创建字体,把字TextOut再用GetPixel()取点存入数组.
缺点:
必须把字TextOut出来,能在屏幕上看见,不爽.
我的方法,用这个函数:
GetGlyphOutline(),可以得到一个字的轮廓矢量或者位图.可以不用textout到屏幕,直接取得字模信息
函数原型如下:
DWORD
GetGlyphOutline(
HDC
hdc,
//画图设备句柄
UINT
uChar,
//将要读取的字符/汉字
uFormat,
//返回数据的格式(字的外形轮廓还是字的位图)
LPGLYPHMETRICS
lpgm,
//
GLYPHMETRICS结构地址,输出参数
cbBuffer,
//输出数据缓冲区的大小
LPVOID
lpvBuffer,
//输出数据缓冲区的地址
CONST
MAT2
*lpmat2
//转置矩阵的地址
);
说明:
uChar字符需要判断是否是汉字还是英文字符.中文占2个字节长度.
lpgm是输出函数,调用GetGlyphOutline()是无须给lpgm
赋值.
lpmat2如果不需要转置,将
eM11.value=1;
eM22.value=1;
即可.
cbBuffer缓冲区的大小,可以先通过调用GetGlyphOutline(……lpgm,
0,
NULL,
mat);
来取得,然后动态分配lpvBuffer,再一次调用GetGlyphOutline,将信息存到lpvBuffer.
使用完毕后再释放lpvBuffer.
程序示例:
(***问题2:
用这段程序,我获取的字符点阵总都是一样的,不管什么字……)
……前面部分省略……
GLYPHMETRICS
glyph;
m2;
memset(&
m2,
sizeof(MAT2));
m2.eM11.value
=
m2.eM22.value
//取得buffer的大小
cbBuf
dc.GetGlyphOutline(
nChar,
GGO_BITMAP,
&
glyph,
0L,
m2);
BYTE*
pBuf=NULL;
//返回GDI_ERROR表示失败.
!
=
GDI_ERROR
pBuf
new
BYTE[cbBuf];
//输出位图GGO_BITMAP
的信息.输出信息4字节(DWORD)对齐
cbBuf,
pBuf,
else
if(m_pFont!
=NULL)
delete
m_pFont;
return;
编程中遇到问题:
一开始,GetGlyphOutline总是返回-1,getLastError显示是"
无法完成的功能"
后来发现是因为调用之前没有给hdc设置Font.
后来能取得pBuf信息后,又开始郁闷,因为不太明白bitmap的结果是按什么排列的.后来跟踪汉字"
一"
来调试(这个字简单),注意到了glyph.gmBlackBoxX
其实就是输出位图的宽度,glyph.gmBlackBoxY就是高度.如果gmBlackBoxX=15,glyph.gmBlackBoxY=2,表示输出的pBuf中有这些信息:
位图有2行信息,每一行使用15
bit来存储信息.
例如:
我读取"
glyph.gmBlackBoxX
0x0e,glyph.gmBlackBoxY=0x2;
pBuf长度cbBuf=8
字节
pBuf信息:
00
08
ff
fc
00
字符宽度
0x0e=14
则
第一行信息为:
0000
100
(只取到前14位)
第二行根据4字节对齐的规则,从0xff开始
1111
110
看出"
字了吗?
呵呵
直到他的存储之后就可以动手解析输出的信息了.
我定义了一个宏#define
BIT(n)
(1<
<
(n))
用来比较每一个位信息时使用
后来又遇到了一个问题,就是小头和大头的问题了.在我的机器上是little
endian的形式,如果我用
unsigned
long
*lptr
(unsigned
long*)pBuf;
//j
from
0
to
15
BIT(j)
//这时候如果想用j来表示写1的位数,就错了
因为从字节数组中转化成unsigned
long型的时候,数值已经经过转化了,像上例中,实际上是0x0800
在同BIT(j)比较.
不多说了,比较之前转化一下就可以了if(
htonl(*lptr)
Unicode中文点阵字库的生成与使用
点阵字库包含两部分信息.首先是点阵字库文件头信息,它包含点阵字库文字的字号、多少位表示一个像素,英文字母与符号的size、起始和结束unicode编码、在文件中的起始偏移,汉字的size、起始和结束unicode编码、在文件中的起始偏移.然后是真实的点阵数据,即一段段二进制串,每一串表示一个字母、符号或汉字的点阵信息.
要生成点阵字库必须有文字图形的来源,我的方法是使用ttf字体.ttf字体的显示采用的是SDL_ttf库,这是开源图形库SDL的一个扩展库,它使用的是libfreetype以读取和绘制ttf字体.
它提供了一个函数,通过传入一个Unicode编码便能输出相应的文字的带有alpha通道的位图.那么我们可以扫描这个位图以得到相应文字的点阵信息.由于带有alpha通道,我们可以在点阵信息中也加入权值,使得点阵字库也有反走样效果.我采用两位来表示一个点,这样会有三级灰度(还有一个表示透明).
点阵字库的显示首先需要将文件头信息读取出来,然后根据unicode编码判断在哪个区间内,然后用unicode编码减去此区间的起始unicode编码,算出相对偏移,并加上此区间的文件起始偏移得到文件的绝对偏移
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 所有 汉字 或者 英文 都是 下面 原理