




已阅读5页,还剩61页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
汉字点阵字模自动生成及镶边处理程序编程开发毕业论文目 录第一章 绪论11.1 课题的综述11.2 设计目标1第二章 准备知识22.1 字体22.1.1 矢量字体22.1.2 点阵字体22.1.3 两者的比较22.2 字符编码32.2.1 字符存储标准32.2.2 GB2312标准32.3 软件42.3.1 VC+6.04第三章 Windows编程与MFC基础63.1 Windows编程基础63.1.1 Windows API函数63.1.2 窗口与句柄63.1.3 事件与消息73.2 MFC基础73.2.1 MFC概述73.2.2 MFC基础类及其层次结构83.2.3 MFC中的全局函数93.2.4 入口函数93.2.5 MFC的消息映射9第四章 点阵字体的生成和显示114.1 提取字体114.1.1 提取系统的指定矢量字体114.2 矢量到点阵的字体转换114.2.1 矢量字体转换为位图114.2.2 位图转换为点阵字体124.3 点阵字体的屏幕显示12第五章 点阵字体的镶边处理145.1 镶边的意义145.2 镶边的方法145.3 镶边的要求145.4 镶边算法的设计155.5 镶边的显示16第六章 软件编程实现176.1 界面制作176.1.1 界面生成176.1.2 控件的设置176.2 点阵字体生成显示模块制作196.2.1 字体的生成196.2.2 字体的显示206.3 镶边模块的制作216.3.1 字体的镶边216.4 字库生成载入模块的制作226.4.1 字库的生成236.4.2 字库的载入246.5 各模块的整合24第七章 程序的改进和不足267.1 改进和完善267.2 程序的不足28结束语29致 谢30参考文献31附录32南京邮电大学2010届本科生毕业设计(论文)第一章 绪论1.1 课题的综述如今,点阵的处理已经被用于各行各业,融入了每个人的生活。众所周知,液晶屏的信息显示其实是相关点阵的显示,比如一个动态场景、一副图像、一个文字或一个符号都是通过一系列点的排列组合来表示的。对于这样一个频繁使用的技术,在其使用中存在很多问题。例如,在一副图像背景中显示一些文字信息。文字的颜色不变,而图像的颜色却不是一成不变的,由此导致两者的对比不明显,文字显示不清晰。本课题所要进行的是点阵字体的屏幕显示和镶边处理。其中主要的镶边处理就是通过在文字周围生成一层不同颜色的边界,从而大大提高文字的可识别度,以解决这一系列的问题。1.2 设计目标利用中文WINDOWS操作系统所带的矢量字库,用VISUAL C+编程实现汉字点阵字模自动生成及镶边处理。所开发的汉字点阵字模自动生成及镶边处理软件须具有下列基本功能:能支持16*16、24*24等多种点阵字模的自动生成;能对每个汉字点阵字模进行自动镶边显示处理。最后以软件代码的形式生成可执行文件,通过界面选项完成对指定字体的显示和镶边处理,并将对应的字体保存成基于GB2312标准的字库文件,以便后续使用。第二章 准备知识2.1 字体2.1.1 矢量字体矢量字体中每一个字形是通过数学曲线来描述的,它包含了字形边界上的关键点,连线的导数信息等,字体的渲染引擎通过读取这些数学矢量,然后进行一定的数学运算来进行渲染。这类字体的好处是字体可以无限放大而不产生变形。而且所需存储量和字符大小无关。矢量字库有很多种,区别在于他们采用的不同数学模型来描述组成字符的线条。常见的矢量字库 Type1 和 TrueType 等。矢量字体的显示分为两步。首先从字库中将它的字符信息读出,然后取出端点坐标,对其进行适当的几何变换,再根据各端点的标志显示出字符。2.1.2 点阵字体在点阵字库中,每个字符由一个位图表示,并把它用一个称为字符掩膜的矩阵来表示,其中的每个元素都是一位二进制数,如果该位为1表示字符的笔画经过此位,该像素置为字符颜色;如果该位为0,表示字符的笔画不经过此位,该像素置为背景颜色。点阵字符的显示分为两步:首先从字库中将它的位图检索出来,然后将检索到的位图写到帧缓冲器中。在实际应用中,同一个字符有多种字体(如宋体、楷体等),每种字体又有多种大小型号,因此字库的存储空间十分庞大,为了减少存储空间,一般采用压缩技术。2.1.3 两者的比较矢量字体具有存储空间小、美观、变换方便等优点。例如:在AutoCAD中使用图形实体-形(Shape)-来定义矢量字符,其中,采用了直线和圆弧作为基本的笔画来对矢量字符进行描述。对于字符的旋转、放大、缩小等几何变换,点阵字体需要对其位图中的每个像素进行变换,而矢量字体则只需要对其几何图素进行变换就可以了,例如:对直线笔画的两个端点进行变换,对圆弧的起点、终点、半径和圆心进行变换等等。而点阵字体的最大缺点就是它是固定分辨率的,也就是每种字库都有固定的大小尺寸,在原始尺寸下使用,效果很好,但如果将其放大或缩小使用,效果就很糟糕了,就会出现我们通常所说的锯齿现象,笔画有参差感,线条不够平滑。因为需要的字体大小组合有无数种,我们也不可能为每种大小都定义一个点阵字库,所以点阵字体是有一定限制的,可能需要根据实际情况生成对应的字库。矢量字体与点阵字体互补优缺,以适应于不同的场合。本文中使用的是Windows自带的矢量字体文件,区别于传统DOS系统下的点阵字体文件,其字体在屏幕显示上更加流畅,美观。2.2 字符编码2.2.1 字符存储标准GB码,全称是GB2312-80信息交换用汉字编码字符集 基本集,1980年发布,是中文信息处理的GBK LOGO国家标准,在大陆及海外使用简体中文的地区(如新加坡等)是强制使用的唯一中文编码。P-Windows3.2和苹果OS就是以GB2312为基本汉字编码,Windows 95/98则以GBK为基本汉字编码、但兼容支持GB2312。GB码共收录6763个简体汉字、682个符号,其中汉字部分:一级字3755,以拼音排序,二级字3008,以偏旁排序。该标准的制定和应用为规范、推动中文信息化进程起了很大作用。1981年5月1日开始实施的一套国家标准,标准号是GB 23121980。它是计算机可以识别的编码,适用于汉字处理、汉字通信等系统之间的信息交换。基本集共收入汉字6763个和非汉字图形字符682个。整个字符集分成94个区,每区有94个位。每个区位上只有一个字符,因此可用所在的区和位来对汉字进行编码,称为区位码。这个码是唯一的,不会有重码字。把换算成十六进制的区位码加上2020H,就得到国标码。国标码加上8080H,就得到常用的计算机机内码。1995年又颁布了汉字编码扩展规范(GBK)。GBK与GB 23121980国家标准所对应的内码标准兼容,同时在字汇一级支持ISO/IEC106461和GB 130001的全部中、日、韩(CJK)汉字,共计20902字。信息交换用汉字编码字符集和汉字输入编码之间的关系是,根据不同的汉字输入方法,通过必要的设备向计算机输入汉字的编码,计算机接收之后,先转换成信息交换用汉字编码字符,这时计算机就可以识别并进行处理;汉字输出是先把机内码转成汉字编码,再发送到输出设备。2.2.2 GB2312标准GB 2312或GB 2312-80是一个简体中文字符集的中国国家标准,全称为信息交换用汉字编码字符集基本集,又称为GB0,由中国国家标准总局发布,1981年5月1日实施。GB2312编码通行于中国大陆;新加坡等地也采用此编码。中国大陆几乎所有的中文系统和国际化的软件都支持GB 2312。GB 2312标准共收录6763个汉字,其中一级汉字3755个,二级汉字3008个;同时,GB 2312收录了包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母在内的682个全角字符。GB 2312的出现,基本满足了汉字的计算机处理需要,它所收录的汉字已经覆盖中国大陆99.75%的使用频率。GB 2312中对所收汉字进行了“分区”处理,每区含有94个汉字/符号。这种表示方式也称为区位码。 01-09区为特殊符号。 16-55区为一级汉字,按拼音排序。 56-87区为二级汉字,按部首/笔画排序。10-15区及88-94区则未有编码。在使用GB2312的程序中,通常采用EUC储存方法,以便兼容于ASCII。浏览器编码表上的“GB2312”,通常都是指“EUC-CN”表示法。每个汉字及符号以两个字节来表示。第一个字节称为“高位字节”(也称“区字节)”,第二个字节称为“低位字节”(也称“位字节”)。“高位字节”使用了0xA1-0xF7(把01-87区的区号加上0xA0),“低位字节”使用了0xA1-0xFE(把01-94加上 0xA0)。由于一级汉字从16区起始,汉字区的“高位字节”的范围是0xB0-0xF7,“低位字节”的范围是0xA1-0xFE,占用的码位是72*94=6768。其中有5个空位是D7FA-D7FE。例如“啊”字在大多数程序中,会以两个字节,0xB0(第一个字节) 0xA1(第二个字节)储存。区位码=区字节+位字节(与区位码对比:0xB0=0xA0+16,0xA1=0xA0+1)。2.3 软件2.3.1 VC+6.0VC+是微软公司开发的一个IDE(集成开发环境),换句话说,就是使用C+的一个开发平台(如图2-1)。VC+应用程序的开发主要有两种模式,一种是WIN API方式,另一种则是MFC方式,传统的WIN API开发方式比较繁琐,而MFC则是对WIN API再次封装,所以MFC相对于WIN API开发更具备效率优势。VC基于C/C+语言,主要由是MFC组成,是与系统联系非常紧密的编程工具,它兼有高级和低级语言的双重性,功能强大,灵活,执行效率高,几乎可说VC在 Windows平台无所不能。最大缺点是开发效率不高。VC适用范围1、 VC主要是针对Windows系统,适合一些系统级的开发,可以方便实现一些底层 的调用。在VC里边嵌入汇编语言很简单;2、 VC主要用在驱动程序开发;3、 VC执行效率高,当对系统性能要求很高的时候,可用VC开发;4、 VC主要适用于游戏开发;5、 VC多用于单片机,工业控制等软件开发,如直接对I/O地址操作,就要用C+;6、 VC适用开发高效,短小,轻量级的COM组件,DLL;7、 VC可以开发优秀的基于通信的程序;8、 VC可以开发高效灵活的文件操作程序;9、 VC可以开发灵活高效的数据库操作程序;10、VC是编CAD软件的唯一选择,包括AUTOCAD,UG的二次开发;11、VC在多线程、网络通信、分布应用方面,VC+有不可比拟的优势。图2-1 VC+开发平台第三章 Windows编程与MFC基础3.1 Windows编程基础Windows操作系统采用了图形用户界面,借助于它提供的API(Application Programming Interface)函数,用户可以编出具有漂亮图形界面的程序。3.1.1 Windows API函数为了方便用户开发Windows应用程序,Windows操作系统提供了各种各样的函数。这些函数是Windows操作系统提供给应用程序编程的接口,简称为API函数。用户在编写Windows程序时所说的API函数,就是指系统提供的函数,所有主要的Windows函数都在“Windows.h”头文件中进行了声明。Windows API也就是Windows操作系统自带的在Windows环境下运行软件开发包(SDK)。程序员总是直接或间接引用API进行应用程序的开发,所以Windows应用程序就有大致相同的用户界面。3.1.2 窗口与句柄窗口是Windows应用程序中一个非常重要的元素,它是Windows应用程序与用户进行交互的接口。一个Windows应用程序至少有一个窗口,称为主窗口。通过窗口,可以接收用户的输入,并显示输出。在Windows应用程序中,窗口是通过窗口句柄(HWND)来标识的。要对某个窗口进行操作,首先就要得到这个窗口的句柄。句柄(handle)是Windows程序中一个重要的概念。在Windows程序中,有各种各样的资源(窗口、图标、光标等),系统在创建这些资源时会为它们分配内存,并返回标识这些资源的标识号,即句柄。Windows中,常用句柄类型及其说明如表3-1所示。表3-1 常用句柄类型及其说明句柄说明句柄说明HWND窗口句柄HDC设备环境句柄HBITMAP位图句柄HCUROR光标句柄HICON图标句柄HFONT字体句柄HMENU菜单句柄HPEN画笔句柄HFILE文件句柄HBRUSH画刷句柄HINSTANCE当前实例句柄HLOCAL局部内存对象句柄HGLOBAL全局内存对象句柄3.1.3 事件与消息Windows程序采用的是事件驱动方式的程序设计模式,其操作主要是基于消息的。在应用程序启动后,系统等待用户在图形用户界面的输入选择,如鼠标按键、键盘按键、窗口被创建、关闭、改变大小、移动等,对系统而言,这些都是事件。只要有事件发生,系统即产生特定的消息。消息描述了事件的类别,包含了相关信息,Windows应用程序利用消息与系统及其他应用程序进行信息交换。由于Windows事件的发生是随机的,程序的执行先后顺序也无法预测,因此系统采用消息队列来存放事件发生的消息,然后从消息队列中依次取出消息进行相应的处理,如图3-1所示。Windows系统消息队列提取消息处理消息事件键盘消息鼠标消息其他消息应用程序图3-1 事件与消息处理3.2 MFC基础前面已经提到,使用Visual C+ 6.0进行应用程序的开发,其最大的便利就是可以使用其提供的MFC库类,通过MFC AppWizard自动生成的MFC应用程序框架,方便地开发自己想要实现的功能。3.2.1 MFC概述Visual C+的微软基础库类(Microsoft Foundation Class Library,MFC)封装了大部分API函数,并提供了一个应用程序框架,简化和标准了Windows程序设计,所以用MFC编写Windows应用程序也称为标准Windows程序设计。MFC约有200个类,提供了Windows应用程序框架和创建应用程序的组件。它提供了大量的基类供程序员根据不同的应用环境进行扩充,同时允许在编程过程中自定义和扩展应用程序中的类。它还具有较好的移植性,可移植于众多的平台。MFC库可以分为3个主要部分:MFC类,宏以及变量(或函数)。如果某个函数或者变量不是类的成员,那么它就是一个全局函数或者全局变量。3.2.2 MFC基础类及其层次结构MFC库类采用单一继承结构,从根类CObject层层派生出绝大多数MFC中的类,如图3-2所示。基类CObject的最基本功能包括支持序列化(serialization)、运行时(Run-time)类的信息获取,提供特定操作符,完成对象的建立与删除。在上述的类库结构中,并没有发现MFC应用程序框架所需要的类:应用类CWinApp、框架类CFrameWnd、文档类CDocument、视图类CView。实际上,它们都是由CCmdTarget为基类派生出来的。CObject 根类CCmdTarget 命令相关类CDC 设备环境类CGdiObject 绘画工具类CMenu 菜单CArray、CList、CMap、群(集合)类CDatabase、CRecordset、ODBC 数据库支持类CDatabase、CDataRecordset、DAO 数据库支持类CFlie 文件类CException 异常类CSyncObject 同步对象类CClientDC、CWindowDCCPaintDC、CPen、CBrush、CFontCBitmap、CPalette、CMenuFile、COlsStreamFile、CSocketFile、CInternetSession 因特网会话类CInternetConnection 因特网连接类CFtpConnectionCGopherConnectionCHelpConnection图3-2 CObject派生类层次示意图3.2.3 MFC中的全局函数MFC库中还包含一些全局函数,这些函数不输入任何一个类,即可以直接使用。这些全局函数一般都以“Afx”为前缀,MFC中主要的全局函数及作用如表3-2所示。表3-2 MFC主要的全局函数及其作用函数名功能AfxBeginThread开始一个新的线程AfxEndThread结束一个旧的线程AfxFormatString类似printf,将字符串格式化AfxMessageBox类似Windows API函数MessageBoxAfxOutputDebugString将字符串输往除错装置AfxGetApp获得application object(CwinApp派生对象)的指针AfxGetMainWnd获得程序主窗口的指针AfxGetInstance获得程序的instance handle3.2.4 入口函数WinMain函数是Windows程序的入口点函数,然而利用AppWizard创建的MFC应用程序中,却找不到WinMain函数。这是因为MFC考虑到典型的Windows程序需要的大部分初始化工作都是标准化的,所以把WinMain函数隐藏在应用程序的框架中,编译时会自动将该函数链接到可执行文件中。应用程序执行时,Windows自动调用应用程序框架内部的WinMain函数。WinMain函数会查找该应用程序的一个全局构造对象,这个对象是由CWinApp派生类构造的,有且只有一个。它是一个全局对象,因此在程序启动时,它就已经被构造好了。随后,WinMain将调用这个对象的InitApplication和InitInstance成员函数,完成应用程序实例的初始化工作。随后,WinMain调用Run成员函数,运行应用程序的消息循环。在程序结束时,WinMain调用AfxWinTerm函数,做一些清理工作。3.2.5 MFC的消息映射Windows程序中的消息处理是在WinProc函数中,通过Switch结构实现的。但当处理的消息比较多时,Switch-Case结构将变得分支很多,影响程序的可读性。而在MFC中,则采用了消息映射的结构进行结构化消息处理。进行MFC消息处理时,程序员要做的就是为每一个要处理的消息提供一个消息处理函数,然后系统通过MFC提供的一套消息映射系统来调用相应的消息处理函数。MFC的消息映射采用消息映射宏的方式,把消息和消息处理函数一一对应起来。在MFC的框架结构下,可以进行消息处理的类的头文件里面都会含有DECLARE_MESSAGE_MAP()宏,这里主要进行消息映射和消息处理函数的声明。MFC把消息分为三大类:窗口消息、控件通知消息和命令消息。第四章 点阵字体的生成和显示4.1 提取字体根据用户的需求,选出指定的字体,常见的字体有宋体、黑体、楷体、仿宋等,将选出的字体指定到当前程序中。4.1.1 提取系统的指定矢量字体系统字体的格式繁多,本文中只针对系统常见的矢量字体文件(后缀名为*.ttf),进行字体提取。TTF(TrueTypeFont)是Apple公司和Microsoft公司共同推出的字体文件格式,随着windows的流行,已经变成最常用的一种字体文件表示方式。在Windows系统中,通常路径C:WINDOWSFonts中存储的就是系统自带的矢量字体库文件。本文根据用户输入的信息(如字体名称)来确定最匹配的矢量字体,并从对应的字体库文件中提取字体的信息交予程序处理。程序中使用MFC的字体类,调用字体对象创建函数来提取矢量字体并创建相应的对象,供程序中调用。本文在提取字体过程中通过指定的函数参数选项,选择系统自带的矢量字体(如在字体建立函数中使用 OUT_TT_ONLY_PRECIS参数,则系统就会自动选择TTF格式的矢量字体文件),将其对应至字体对象中。之后在使用字体对象描绘字体的时候,绘出的就是对应字体库中取出的字体。4.2 矢量到点阵的字体转换矢量字体转换为点阵字体的方法有很多,本文中采用的方法是先将矢量字体转换为位图字体,然后将位图字体转换为点阵的矩阵形式。4.2.1 矢量字体转换为位图矢量字体转换为位图,类似于按照字体的大小和格式在屏幕中显示矢量字体,绘出字体的曲线,然后对屏幕中的字体进行截图操作,以截取不同样式的字体图片,由于在嵌入式显示应用中使用较多,且不能每次要使用点阵字体就去截图,这样的效率并不理想,于是Windows中提供了一种方法可以方便快捷地提取位图信息,借此生成点阵库文件,而最终在嵌入式的显示屏上使用的大多是在点阵库中提取点阵信息。首先通过字体提取得到矢量字体信息,之后通过系统函数将矢量信息转换为位图信息。其具体实现过程为:先根据矢量字体的格式在屏幕上显示描绘出字体的笔画曲线,之后从屏幕上按像素取点,根据所需转换的字体尺寸取出对应个数的像素块,并对每个像素块进行灰度平均,如此即得到一个字符的位图信息。本文中使用的系统函数得到的位图信息,并不是通常所想的二维矩阵的表现形式,而是将位图中的后一行数据接在前一行数据之后,由此得到的一条位图数据带,在这一行中存储了位图中每一行的数据,在进行之后的数据转换过程中,要考虑到数据的位移和对应的下标变化。4.2.2 位图转换为点阵字体位图信息还不是点阵字体,需要一定的转换。所谓的位图信息可以理解为对一个字符的灰度图,其值在0255之间,而点阵的要求是只有两种灰度值,通常为黑白两色,其实也就是黑白位图的形式,所以需要对位图信息进行0-1的值归一,并按照行列的规定点数排列,这样就转换为真正的点阵字体了。其点阵数据类似于图4-1。图4-1 点阵数据的表示如图中所示,位图信息已经转换成点阵的矩阵形式,也就是将位图的数据按固定的列数进行分行,并将其中的灰度值进行类似阈值分割的操作。在本文中使用的函数会自动生成位图信息,并将其进行灰度的平均,将最后的结果进行阈值分割,形成单色位图,并以字节的形式存储。而实际中,需要对矢量字体进行取点操作,按所选的点阵尺寸选出对应的像素块,并取得相应的灰度值,之后对每个像素块进行灰度的平均操作,将各块的平均值保存至一个新的矩阵中,其后对新的矩阵进行阈值分割,使其字体的笔画和背景区分开来,如此便得到了字符的点阵表示。4.3 点阵字体的屏幕显示点阵字体的屏幕显示,也就是在屏幕上按照点阵数据的排列在相应的坐标处绘出对应的点。其显示的结果类似于图4-1中的结果,在绘图时,要求注意绘点的尺寸及绘点的坐标位置,特别是每一行的起始位置和每一列的起始位置。对应的画图命令由MFC中的画笔和画刷应用对应的函数完成画图命令。程序中使用画笔在指定的位置描绘点阵字体的每个点,如程序描绘一个“我”字,则根据存储的数据描绘每一行,第一行为000010101000,对于0即描绘一个白点,对于1则描绘一个黑点,如此反复,直至描绘出整个字体。示例中的点阵的存储是根据字节来存储的,这样方便计算机存储和管理,而实际应用中由于考虑到算法的通用性,在选择数据存储的方式上,选择了使用矩阵的形式来存储点阵,即使用一个字节的空间来存储一个点的数据,虽然这样数据空间利用率有所降低,但是在计算处理时间上,及算法的通用性上得到了相应的改善,使得对应点的寻址更加方便快捷。第五章 点阵字体的镶边处理5.1 镶边的意义点阵是日常生活中频繁使用的技术,其中也存在很多问题。例如,在一副图像背景中显示一些文字信息。文字的颜色不变,而图像的颜色却不是一成不变的,由此导致两者的对比不明显,文字显示不清晰。其中主要的镶边处理就是通过在文字周围生成一层不同颜色的边界,从而大大提高文字的可识别度,以解决这一系列的问题。5.2 镶边的方法字体镶边的方法有多种,有的是对矢量字体进行镶边,有的是对点阵字体进行镶边。对矢量字体镶边,其实是根据计算矢量字体的曲线时,在笔画的周围再添一条线,由此得到镶边的效果。对点阵字体的镶边,其实是对点阵字体的点阵数据进行处理,在笔画点的周围加一圈点,由此得到镶边的效果。无论哪一种方法,都有软件实现和硬件实现两种方法。而其镶边算法还有实时和静态两种情况。本文中使用的是对点阵字体镶边的实时软件实现方法。5.3 镶边的要求由于点阵字体的实用频繁,这就对镶边算法有一定的要求。首先,在显示过程中避免不了大量文字的显示处理,对镶边算法的速度就有一定的要求。采用静态镶边算法是不存在此问题的,由于之前就已经对字体完成镶边,显示时只是多显示一层边而已,对速度的影响不大;而此时实时的算法由于需要边镶边边显示,因此对算法的时间复杂度有一定的要求。但另一方面,处理大量文字也就意味着需要大量的存储空间,对镶边算法的空间占用就有一定的要求。在静态镶边过程中需要大量的存储空间存储镶边后的字体,这就对镶边算法的空间复杂度有一定的要求;而此时实时的算法由于是边镶边边显示,所以所需的空间很少,基本用处理一个字体的空间存储就足够了。其次,在点阵的显示中,还存在字体是否美观的问题,这就对镶边算法的美观性有一定的要求。例如对字体较小或者显示的点阵点数不是很多的情况下,镶边算法的结果不是仅仅将字体包住就可以的,考虑到美观的要求,应该在点相对密集的地方适当地减少镶边的点数,即紧凑的笔画之间镶边点数可适当减少,以避免镶边点数过多而引起字符形状不清晰的情况。在实际应用中还有一些其他的要求,在本文中暂时不考虑这些特别的因素。5.4 镶边算法的设计 根据本文使用的镶边实现方法和镶边算法的一些要求,设计镶边算法的大体框架。首先需要将点阵字体的数据处理成对应尺寸的矩阵形式(如16*16,24*24)。然后按照行列遍历矩阵,判断每一个点是否为边界点,如果是边界点即输出边界,如果不是边界点就跳过。判断边界点的算法为:判断此处是否有笔画存在,如果有笔画存在则不是边界点,如果此处不存在笔画即进行下一步的判断,判断此点周围的8个点中是否有笔画存在,如果有的话则此点为边界点,若周围没有笔画存在时则此点不是边界点。其算法流程如下图5-1读入点阵数据矩阵遍历行列取出一个点该点是否有笔画存在该点周围是否有笔画存在镶边显示矩阵是否遍历结束镶边结束是否是否是否图5-1 镶边算法的流程图5.5 镶边的显示在镶边过程中,镶边的显示也是一个值得考虑的问题。由于不同的镶边算法,其显示方法有所不同,对于本文中讨论的点阵字体实时软件实现方法而言,其镶边的显示也有两种方法。其一为字体和边界分开显示,先显示字体点阵,在根据字体形状显示镶边后的边界;其二为字体和边界同时显示的方式,在显示字体的过程中,同时加入边界的判定和显示。在本文中,采用第二种方法。先根据具体的字体信息生成矩阵形式的点阵数据,之后遍历数据取点描绘,同时判定边界,用另一种对比度大的颜色描绘边界,如此实现镶边功能。第六章 软件编程实现6.1 界面制作本文采用MFC类库定制程序界面。6.1.1 界面生成首先打开VC+6.0软件,然后新建项目工程,名称为MyPro,类型为MFC AppWizardexe,根据菜单选项选择基于对话框模式,点击下一步,可设置窗口标题,在下一步可以选择编译方式,为了在其他Windows平台也可以运行此程序,编译选项使用静态编译库,即勾选As a statically linked library。建立项目文件后,向导会自动生成项目的一些所需文件,此时程序已经可以运行,结果为一个空白对话框,任意点击按钮即关闭程序。展开resources浏览项中的Dialog,点击DIALOG界面资源,即可浏览编辑界面,可将旁边的工具栏中的控件资源拖入对话框中,由此构建程序界面如图6-1所示。图6-1 程序界面结构6.1.2 控件的设置界面中诸如文本框、下拉框、按钮等都属于控件,要改变控件属性,使这些控件与程序关联起来,就需要对它们进行设置。右击控件可以调出对应的属性,如控件名称、边界属性、文本对齐方式等信息,可以对其编辑改变控件的属性。对于文本编辑框Edit,可以改变输入框的显示方式,是否只许输入数字,输入信息的对齐方式等信息。对于下拉框ComboBox,可以预设下拉框中的下拉选项数据,及下拉框的类型,是否允许编辑框中的信息或添加新的选项等。对于按钮Button,可以选择按钮显示类型,编辑按钮文字等。程序中还要设置控件与变量的映射关系。在界面编辑中,按Ctrl+W调出映射关系表,设置控件与变量及消息的映射关系。对于控件与变量的关系,通过Member Variables进行设置。例如文本编辑框的变量设置如图6-2所示。图6-2 文本框变量对应设置图6-2中设置了文本框的数据变量m_input,格式为CString,文本框中允许输入的字符长度为12。变量的数据类型有数据变量和控制变量两种,根据不同的情况使用不同的变量,对于文本输入信息等使用数据变量,可以直接访问用户输入的数据,而对于下拉框则使用控制变量CComboBox,以便调用其相关函数选取处理数据,如设置初始选项,获得当前选项等。对于消息映射,则通过Message Maps进行设置。如对按钮的单击事件产生的消息进行处理,就需要添加消息处理函数,如图6-3所示。图6-3 按钮消息事件处理图6-3中,按钮消息表中的BN_CLICKED消息为按钮单击消息,而下面的对应函数中的OnShow1函数就是处理这个消息所对应的方法。6.2 点阵字体生成显示模块制作点阵字体的生成模块是把矢量字体载入并转换为点阵字体,而显示模块是把每个字的点阵数据通过画图函数画在屏幕上。6.2.1 字体的生成定义CFont字体类的对象,之后根据用户输入的字体类型及点阵尺寸建立新的字体,关键代码如下:CFont cFont;cFont.CreateFont(nHeight, OUT_TT_ONLY_PRECIS, LPCTSTR(fontname);上述代码建立了一个尺寸为nHeight大小的,字体名称为fontname的字体,其中的OUT_TT_ONLY_PRECIS参数指定系统使用TTF的字体文件。建立字体过程中,Windows会自动检索字体库文件,找到与提供信息最匹配的字体文件,如fontname的值为“宋体”,则系统自动找寻宋体的字库文件。之后,通过dc-SelectObject(&cFont)命令将该类字体送入设备环境中,此时在此设备中输出地字体就是所选的字体,这就完成了字体的载入过程。此时,使用m_input变量获取用户在界面的文本框中输入的字符信息,通过(m_input.GetAt(0) & 0x00ff)8) + (m_input.GetAt(1) & 0x00ff)命令,获得输入的字符代码,即对应字符的区位码加上0xA0A0,用一个字符变量nChar存储字符代码。然后通过系统自带的功能函数GetGlyphOutline(nChar, GGO_BITMAP, &gm, cBuf, pBuf, &mat2),将nChar对应的字符转换成比特图的形式,生成比特图的大小保存在cBuf中,而比特图的数据保存在pBuf中。再从pBuf中取出各行各列的数据存在一个数组中,该数组即为点阵字体的数据矩阵。其关键代码为:btCode = pBufi* nByteCount + j;for (int k = 0; k k) borderl+ = 1;else borderl+ = 0;其中btCode从pBuf中取出一个字节,再按位判断每个比特,按0-1存入数组border中。程序中nByteCount的值为(gm.gmBlackBoxX +31) 5) 2,这是因为GetGlyphOutline函数的默认格式的影响。GetGlyphOutline函数将比特图的每一行保存成32个比特的整数倍,也就是4个字节的数据为一组,如16x16的点阵尺寸,生成的pBuf的每一行应有16个点的值,也就是每一行只需2个字节就能保存,而实际上每一行却有4个字节的存储空间,前两个字节保存点的值,余下的2个字节函数默认为0,所以在将pBuf中的数据保存至数组中时,应注意行列的标号。6.2.2 字体的显示字体的显示是通过在对应点处画出一个小矩形来表示一个点,而一系列点的排列构成了一个字符。其关键代码如下:for (int i = 0; i gm.gmBlackBoxY; i+)for (int j = 0; j SelectStockObject(WHITE_BRUSH);dc-Rectangle(m, n, m + sizex, n + sizey);n += sizey;m = startx;其中nx的值为(gm.gmBlackBoxX + 7) 3,其意义为每一行所对应的字节数,比如16x16的点阵字体,一行有16个点,而8个点的数据保存为一个字节,则其每一行就有2个字节,其nx的值为2代码通过遍历点阵数据找寻值为1的点,即有笔画的点,对这样的点进行屏幕绘图,使用SelectStockObject(WHITE_BRUSH)载入白色的画刷来填充每个点的颜色,再用Rectangle(m, n, m + sizex, n + sizey)画出一个sizex*sizey大小的矩形,以此来表示一个点,而其中的m,n表示的是该点的起始行列位置。要注意的是,每显示一个点n的值都需要增加一个sizey,而m不变,但当一行结束后m,n的值需要改回起始处,否则下一行的点会偏离预定的地方。如图6-4为24*24宋体格式的“我”字的显示结果。图6-4 “我”字的点阵显示6.3 镶边模块的制作镶边模块是建立在显示模块之上的,由于采用的是实时的镶边算法,只需在显示的过程中增加边界判断即可,其代码大多类似于显示模块的。6.3.1 字体的镶边在显示模块的基础上,改变显示的条件,将if (border8 * nx * i + j = 1)改为if(MyIsBorder(j, i, 8 * nx, gm.gmBlackBoxY) & border8 * nx * i + j != 1),将画刷的颜色改为黑色即可,绘出的黑色点即是边界,而白色的点就是笔画。其中关键的就是MyIsBorder这个边界判断函数,此函数判断该点周围是否有笔画存在,其算法为:依次判断该点周围的8个点是否存在且有笔画,一旦周围有笔画就返回TRUE值,否则就返回FALSE值。其关键代码为:if (ty - 1 = 0) /判断当前点上一行是否存在/判断当前点左上方是否存在且有笔画if (tx - 1 = 0 & border(ty - 1) * xmax + tx - 1) return TRUE;/判断当前点上方是否存在且有笔画if (border(ty - 1) * xmax + tx) return TRUE;/判断当前点右上方是否存在且有笔画if (tx + 1 xmax & border(ty - 1) * xmax + tx + 1) return TRUE;return FALSE;上述代码中,tx为列, ty为行, xmax为最大列数, ymax为最大行数,以此来判断边界信息。镶边的结果如图6-5所示。图6-5 “我”字的镶边显示结果我们可以比较镶边前后的显示结果,如图6-6所示,从图中我们可以明显地看出镶边前后点阵字体与背景对比度的差异,镶边前的“我”字并不十分清晰,而镶边后的“我”字却很清晰,更加容易辨识,这就达到了我们镶边的目的。图6-6 “我”字的镶边前后比较6.4 字库生成载入模块的制作根据GB2312的区位格式,生成指定字体的字库,并实现载入功能。6.4.1 字库的生成在界面中定制一个生成字库的按钮,并添加按钮点击事件处理函数。在此函数中,遍历所有的区位码,将生成的点阵信息按比特存入文件中。此过程中,需要用到MFC中的CFile类库,其中的函数可以定制文件的读写方式,权限及格式等,打开文件的关键代码为:CString strFilter, strFileName;strFilter = 自制点阵字库 MyDot File (*.mydot)|*.mydot|;/定义过滤字符串/创建保存文件对话框对象,默认的文件扩展名为:.mydotCFileDialog fdlg(FALSE, mydot, NULL, OFN_EXPLORER|OFN_HIDEREADONLY|OFN_ENABLESIZING|OFN_FILEMUSTEXIST,strFilter);if (fdlg.DoModal() = IDOK)/显示文件保存对话框strFileName = fdlg.GetPathName();/获取文件名/构造CFile对象CFile myfile(strFileName, CFile:modeCreate|CFile:modeWrite);其中,CFileDialog建立了一个保存文件对话框(如图6-7所示),并定义文件的后缀名为*.mydot,而myfile对象建立了一个指向生成字库文件的文件指针,通过CFile类中的Write函数可以方便地向文件中写入所要保存的数据。写入字库数据时,通过循环区位码,调用GetGlyphOutline函数按6.2.1中字体生成的方法得到点阵的矩阵数据,再用myfile.Write(&btCode, sizeof(BYTE)函数将对应的字节信息写入至文件中即可,要注意的是有些字符的行列数并不一定是所指定的尺寸大小,如字符“一”,它的行数很小,但是存放至字库的时候每一个字符都是分配指定大小的空间,需要对空白的部分进行补零的操作,在程序中则由btCode = (k gm.gmBlackBoxY) & (l nx) ? pBufk* nByteCount + l : 0命令来进行补零。在文件对象不使用时,需要用Close()命令关闭文件对象。图6-7 生成字库保存对话框6.4.2 字库的载入字库的载入和生成有相似之处,都是文件的操作,使用的都是CFile类库,不同的是一个是写入,一个是读取。在上一节生成字库时,使用的是按顺序写入的方法,但读取的时候可能需要读取文件的某个特定的位置,这就对文件定位有了一定的要求。首先还是使用CFileDialog类,不过现在是建立打开文件对话框,只要将对话框命令中的FLASE值改为TRUE即可,命令如:CFileDialog fdlg(TRUE, mydot, *.mydot, OFN_HIDEREADONLY|OFN_FILEMUSTEXIST,strFilter),使用fdlg.DoModal()命令调出对话框,使用fdlg.GetPathName()命令可以得到用户想要打开的文件的路径名称。然后使用CFile myfile(FileName, CFile:modeRead)命令构造指定字库文件的读取指针,根据用户输入的区位码信息设置文件偏移量offset = (qu - 1) * 94 + wei - 1) * dotsz * dotsz / 8,再通过myfile.Seek(offset, CFile:begin)命令可以是文件指针指向所需的数据位置,之后使用myfile.Read(&btCode, sizeof(BYTE)函数,即可方便地从指定的位置读取所需字符的字节信息,并存至btCode变量中,这是只需根据前几节中的内容即可实现字符的显示,甚至镶边处理。6.5 各模块的整合各个模块都完成以后就可以进行整合,整合的目的是让每个模块组合在一起,形成一个完整的功能,并将可以提取的部分抽象出来。在整合的过程中,要避免模块之间的冲突,调整变量的影响范围,使得功能的实现先后不影响结果,并将整体中存在的问题进行修整。主要的就是显示模块和镶边模块的整合处理。在显示之前不能进行镶边处理,为解决这一问题,在镶边函数起始处加一条判断信息,判断显示按钮是否按下。程序运行时由于是基于对话框模式,因此当按下回车或Esc健的时候,对话框就自动结束,程序即关闭了,为了解决这一问题,需要重新定义OnOK、OnCancel函数,重新指定确定和取消键的执行结果,然后还要重新定义ON_WM_CLOSE关闭消息
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 鹰潭市中储粮2025秋招笔试行测高频题库及答案
- 防城港市中储粮2025秋招笔试题库含答案
- 小学语文1-6年级“根据偏旁写汉字”15个集锦
- 中国广电龙岩市2025秋招计算机类专业追问清单及参考回答
- 中国移动邵阳市2025秋招半结构化面试模拟30问及答案
- 中国联通安徽地区2025秋招笔试模拟题及答案
- 自媒体创业测试题及答案
- 2025年手工黏土考试题及答案
- 淮南市中石化2025秋招笔试英语专练题库及答案
- 天津市中石化2025秋招面试半结构化模拟题及答案机械与动力工程岗
- 2025年“学宪法、讲宪法”主题活动知识竞赛题库及答案
- 2024年毕节威宁自治县招聘城市社区工作者真题
- 医院感染管理办法
- 2025年电子专用设备制造行业研究报告及未来行业发展趋势预测
- BIM 建模基础与应用教学教案
- 法院调令申请书范本
- GB/T 23451-2023建筑用轻质隔墙条板
- 驻足思考瞬间整理思路并有力表达完整版
- 第二章 盛唐诗歌边塞诗派公开课一等奖课件省赛课获奖课件
- 滚筒干燥机设计毕业设计
- 真空包装机作业指导书
评论
0/150
提交评论