点阵字库的原理.docx

上传人:b****5 文档编号:5787056 上传时间:2023-01-01 格式:DOCX 页数:21 大小:807.33KB
下载 相关 举报
点阵字库的原理.docx_第1页
第1页 / 共21页
点阵字库的原理.docx_第2页
第2页 / 共21页
点阵字库的原理.docx_第3页
第3页 / 共21页
点阵字库的原理.docx_第4页
第4页 / 共21页
点阵字库的原理.docx_第5页
第5页 / 共21页
点击查看更多>>
下载资源
资源描述

点阵字库的原理.docx

《点阵字库的原理.docx》由会员分享,可在线阅读,更多相关《点阵字库的原理.docx(21页珍藏版)》请在冰豆网上搜索。

点阵字库的原理.docx

点阵字库的原理

点阵字库的原理 2010-12-0617:

12:

46

分类:

点阵字库的原理(引文)

所有的汉字或者英文都是下面的原理,

由左至右,每8个点占用一个字节,最后不足8个字节的占用一个字节,而且从最高位向最低位排列。

生成的字库说明:

(以12×12例子)

一个汉字占用字节数:

12÷8=1····4也就是占用了2×12=24个字节。

编码排序A0A0→A0FEA1A0→A2FE依次排列。

以12×12字库的“我”为例:

“我”的编码为CED2,所以在汉字排在CEH-AOH=2EH区的D2H-A0H=32H个。

所以在12×12字库的起始位置就是[{FE-A0}*2EH+32H]*24=104976开始的24个字节就是我的点阵模。

其他的类推即可。

英文点阵也是如此推理。

在DOS程序中使用点阵字库的方法

   首先需要理解的是点阵字库是一个数据文件,在这个数据文件里面保存了所有文字的点阵数据.至于什么是点阵,我想我不讲大家都知道的,使用过"文曲星"之类的电子辞典吧,那个的液晶显示器上面显示的汉子就能够明显的看出"点阵"的痕迹.在PC机上也是如此,文字也是由点阵来组成了,不同的是,PC机显示器的显示分辨率更高,高到了我们肉眼无法区分的地步,因此"点阵"的痕迹也就不那么明显了.

   点阵、矩阵、位图这三个概念在本质上是有联系的,从某种程度上来讲,这三个就是同义词.点阵从本质上讲就是单色位图,他使用一个比特来表示一个点,如果这个比特为0,表示某个位置没有点,如果为1表示某个位置有点.矩阵和位图有着密不可分的联系,矩阵其实是位图的数学抽象,是一个二维的阵列.位图就是这种二维的阵列,这个阵列中的(x,y)位置上的数据代表的就是对原始图形进行采样量化后的颜色值.但是,另一方面,我们要面对的问题是,计算机中数据的存放都是一维的,线性的.因此,我们需要将二维的数据线性化到一维里面去.通常的做法就是将二维数据按行顺序的存放,这样就线性化到了一维.

   那么点阵字的数据存放细节到底是怎么样的呢.其实也十分的简单,举个例子最能说明问题.比如说16*16的点阵,也就是说每一行有16个点,由于一个点使用一个比特来表示,如果这个比特的值为1,则表示这个位置有点,如果这个比特的值为0,则表示这个位置没有点,那么一行也就需要16个比特,而8个比特就是一个字节,也就是说,这个点阵中,一行的数据需要两个字节来存放.第一行的前八个点的数据存放在点阵数据的第一个字节里面,第一行的后面八个点的数据存放在点阵数据的第二个字节里面,第二行的前八个点的数据存放在点阵数据的第三个字节里面,…,然后后面的就以此类推了.这样我们可以计算出存放一个点阵总共需要32个字节.看看下面这个图形化的例子:

   ||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|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;   /*控制行*/

   int    j;   /*控制一行中的8个点*/

   int    k;   /*一行中的第几个"8个点"了*/

   int    nc;  /*到点阵数据的第几个字节了*/

   int    cols;/*控制列*/

   BYTE   staticmask[8]={128,64,32,16,8,4,2,1};/*位屏蔽字*/

   w=(w+7)/8*8;/*重新计算w*/

   nc=0;

   for(i=0;i<=""font=""style="word-wrap:

break-word;">

   {

   cols=0;

   for(k=0;k<=""font=""style="word-wrap:

break-word;">

   {

   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等),一个系统中已有的字体名称列表,一个预览按钮,一块画图显示区域.

   得到字体列表的方法:

(作者称这一段是用来取回系统的字体,然后添加到下拉框中)

   //取字体名称列表的回调函数,使用前要声明一下该方法

   int  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  )

   pWnd->m_combo_sfont.AddString(lpelf->elfLogFont.lfFaceName);

   return  1;

   }

   return  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,                //将要读取的字符/汉字

   UINT  uFormat,            //返回数据的格式(字的外形轮廓还是字的位图)

   LPGLYPHMETRICS  lpgm,    //  GLYPHMETRICS结构地址,输出参数

   DWORD  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;

   MAT2  m2;

   memset(&m2,  0,  sizeof(MAT2));

   m2.eM11.value  =  1;

   m2.eM22.value  =  1;

   //取得buffer的大小

   DWORD  cbBuf  =  dc.GetGlyphOutline(  nChar,  GGO_BITMAP,  &glyph,  0L,  NULL,  &m2);

   BYTE*  pBuf=NULL;

   //返回GDI_ERROR表示失败.

   if(  cbBuf  !

=  GDI_ERROR  )

   {

   pBuf  =  new  BYTE[cbBuf];

   //输出位图GGO_BITMAP  的信息.输出信息4字节(DWORD)对齐

   dc.GetGlyphOutline(  nChar,  GGO_BITMAP,  &glyph,  cbBuf,  pBuf,  &m2);

   }

   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  00  00  ff  fc  00  00

   字符宽度  0x0e=14    则  第一行信息为:

          0000  0000  0000  100      (只取到前14位)

   第二行根据4字节对齐的规则,从0xff开始        1111  1111  1111  110

   看出"一"字了吗?

呵呵

   直到他的存储之后就可以动手解析输出的信息了.

   我定义了一个宏#define  BIT(n)    (1<<(n))    用来比较每一个位信息时使用

   后来又遇到了一个问题,就是小头和大头的问题了.在我的机器上是little  endian的形式,如果我用

   unsigned  long  *lptr  =  (unsigned  long*)pBuf;

   //j  from  0  to  15

   if(  *lptr  &  BIT(j)  )

   {

   //这时候如果想用j来表示写1的位数,就错了

   }

   因为从字节数组中转化成unsigned  long型的时候,数值已经经过转化了,像上例中,实际上是0x0800  在同BIT(j)比较.

   不多说了,比较之前转化一下就可以了if(  htonl(*lptr)  &  BIT(j)  )

Unicode中文点阵字库的生成与使用

   点阵字库包含两部分信息.首先是点阵字库文件头信息,它包含点阵字库文字的字号、多少位表示一个像素,英文字母与符号的size、起始和结束unicode编码、在文件中的起始偏移,汉字的size、起始和结束unicode编码、在文件中的起始偏移.然后是真实的点阵数据,即一段段二进制串,每一串表示一个字母、符号或汉字的点阵信息.

   要生成点阵字库必须有文字图形的来源,我的方法是使用ttf字体.ttf字体的显示采用的是SDL_ttf库,这是开源图形库SDL的一个扩展库,它使用的是libfreetype以读取和绘制ttf字体.

   它提供了一个函数,通过传入一个Unicode编码便能输出相应的文字的带有alpha通道的位图.那么我们可以扫描这个位图以得到相应文字的点阵信息.由于带有alpha通道,我们可以在点阵信息中也加入权值,使得点阵字库也有反走样效果.我采用两位来表示一个点,这样会有三

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 经管营销 > 销售营销

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1