摘要:为了得到高质量而且灵活(包括对字形的各种变形操作)的字符显示,同时又能实现所见即所得(WYSIWYG)的打印,传统的使用点阵字库的方法已经不能满足要求,有一个很好的方法——使用TrueType字库,可以同时解决以上两个问题.介绍了TrueType技术的基本原理及在Vxworks系统中如何通过FreeType应用TrueType字库,在实际应用中,该技术很好地解决了上述问题,但这种技术也可以很容易地移植到很多其他系统中,如Linux。 关键词:VxWorks;TrueType;UGL字体驱动;打印 与传统的使用点阵字库相比,TrueType字库至少会带来这样的好处:可以高质量地实现字符的无级放大或缩小,高质量地实现字符的旋转、倾斜等操作(如图1),方便地实现“所见即所得”. 图1应用效果图 由于有以上优点,在很多对字形有特殊操作要求的地方最好使用TrueType字库.Windows中现在使用的就是TrueType字库。 l、TrueType字库的基础 1.1 TrueType简介 TrueType字库是一种轮廓字库,在True—Type字库中,字形的信息是通过使用一系列的点来描述的.这些点之间或通过直线段,或通过二次贝塞尔曲线来连接,从而形成字形轮廓.图2是汉字“乾”的字形示例。 图2字形轮廓线示例 图2左边图形是直接连接字库中描述“乾”的点形成的,其中的圈表示描述字形的点:小圈表示直线段或贝塞尔曲线的端点,大圈表示贝塞尔曲线的控制点. 形成字形轮廓时对点的处理是这样的:假设有了起点P0(x0,y0)(它肯定是端点,即小圈),再找下一个点P1(x1,y1).如果P1也是端点,则用直线段连接P0,P1,再将P1作为新的起点继续连接剩下的点;否则P是贝塞尔曲线控制点,再找下一个点P2(x2,y2).如果P2是端点,则将P0,P1,P2用贝塞尔曲线连接,P2作为新的起点继续连接剩下的点;否则再找下一个点P3(x3,y3),计算P2与P3的中点Px,将P0,P1,Px用贝塞尔曲线连接,Px作为新的起点继续连接剩下的点.图2右边的图形是加入了二次贝塞尔曲线形成的实际见到的字形轮廓. 得到字型轮廓后,再对它进行填充就得到了需要的字符位图.剩下的工作就很简单了,通过打点或贴图都可以画出字符来. 1.2 FreeType的介绍 使用TrueType字库也有一定的困难:主要就是需要对TrueType字库的格式要有所了解。这样才能正确地提取出字形信息,而这对大多数用户来说很困难,也是很麻烦的.但是现在有了FreeType这个开放源码的共享软件(可以从网上下载),就不必亲自做这些工作了.FreeType可以在很多平台下编译并使用(如Windows、Linux、VxWorks等).利用FreeType提供的API,得到字形信息,形成位图等工作都可以很方便地完成. 1.3 FreeType使用 FreeType提供了丰富的API,具体用法可以参见其文档,这里仅作简要介绍. 用FreeType的API画出一个字符的流程大致如下(仅列出函数名): …… /*初始化 FreeType库 */ FT_Init_FreeType; /*建立字体,如宋体 、楷体等 */ FT_New_Face: /*指定查找字符字形的编码,如 Unicode、 GB2312等 *| FT_Select Charmap …… /*根据字符编码得到字符字形在字库中的位置 */ FT_Get_Char_Index: /*根据字符字形在字库中的位置得到其字形描述,即字形轮廓*/ FT_Load_Glyph: /*将轮廓填充成位图*/ FT_Render_Glyph: /*用户自定义函数画出位图*/ Drawimage; …… /*撤消字体*/ FT_Done_Face: /*撤消FreeType库*/ FT_Done_FreeType; …… 当然实际系统中的应用不会这么简单,但是其基本过程是这样的。 2、UGL字体驱动 UGL是Zinc的基础,首先在Vxworks的UGL字体驱动中加入TrueType字库支持: 1)根据VxWorks的UGL字体驱动的接口标准写出驱动代码. 2)用行命令方式编译UGL.在UGL文档中介绍了行命令方式编译UGL,以及为加入新字库支持而修改相关文件(如uglnit.h等)的方法. 现有UGL字体驱动只提供了用于水平方向字符显示的接口,为了能够更加灵活地显示字符,可以在驱动接口中增加函数指针UGL-STATUS(*textDrawFree);为了支持打印,可以加入函数指针UGL-STATUS(*textPrint).当然如果用户要调用这2个函数,就得在ugl.h中加入相应的函数声明,并在uglfont1.c中加入相应的函数定义. typedef struct ugl-font-driver { /*原来的驱动接口*/ …… /*新加入的驱动接口*/ UGL_STATUS(*textDrawFree) (structu ug_lgc * pGc, const char * text, unsigned long length, const UGL_TT_PARAM * param); UGL_STATUS(*textPrint)(struct ugl_font_driver * pFontDriver, const char * pFaceName。 FILE * outfile, const char* text, int length, const UGL_TT_PARAM * param); }UGL-FONT-DRIVER; textDrawFree中的结构UGLrr_PARAM中,定义了一些要用到的参数,如大小、前景及背景颜色、旋转角度、倾斜程度等. 另外,为了提高字符显示速度,可以用下面的方法: 1)将TrueType字库调人内存.即用FT_New_Memory_Face代替FT_New_Face; 2)利用FreeType提供的缓存功能.具体用法可以参见FreeType提供的文档. 3)对固定尺寸的字体(一般用于界面,这种情况下对速度有较高的要求)专门建立一个Cache.现举例说明如下: 假设Cache的结构如下: struct tt_cache_ { /*code_aray存储字符编码*/ unsigned long code_aray[TT_CACHE_NUM]; /*cache_glyph存储相应的位图*/ struct tt_glyph_cache_glyph[TT_CACHE_NUM]; }; TT_CACHE_NUM是需要建立Cache的字符数量.一般来说,Cache中应包括ASCII可显示字符、汉字中的一级字及一些常用符号. 1)假设tt_cache一>code_aray中已经存储了需要建立Cache的字符编码,首先对它排序(用C语言的qsort即可): qsort(tt_cache—>code_array,TT_CACHE_NUM,sizeof(unsignedlong),compare); 2)为所有字符生成相应的位图. 3)系统运行过程中需要查找字符的字形时,执行以下步骤: ①用bsearch在tt_cache一>code_aray中查找字符编码. ②若查找到,则相应的位图也找到了. ③若没查找到,则到字库中去找. 4)销毁字体时要同时销毁Cache. 应该注意的是上面的步骤1)、2)是在系统启动时做的,如果第2)步时间太长的话,可以不执行步骤2),只需改变步骤3): ①用bsearch在tt_cache一>code_aray中查找字符编码. ②若查找到,再看相应的位图是不是存在.如果已经存在,则相应的位图也找到了.如果还没有,则根据字库生成位图,并添加到Cache中. ③若没查找到,则到字库中去找. 实践证明,这种方法稍好一点. 3、打印 下面介绍在窗口系统Zinc中利用UGL字体驱动如何实现打印中的“所见即所得”. Zinc中的打印流程是:先生成PS(PostScript)文件,再把PS文件发到打印机端口进行打印,所以下面只讨论如何生成PS文件. 由于现有系统Zinc不支持汉字的打印,所以必须回到UGL中用打点的方式画出汉字.这就是为什么实现UGL字体驱动时要加人函数指针UGL_STATUS(*textPrint)的原因. textPrint中的参数意义为: pFaceName字体名,如宋体、黑体等; outfile指向打印的输出目标:PS文件. 修改Zinc中的ZafPrinter,当要打印字符时就调用UGL中的打印函数,UGL中实现打印的部分基本与屏幕显示相同,不同的只是把向屏幕(或内存位图)打点(或贴图)换成了向PS文件写人打点(或贴图)命令. 由于打印和屏幕显示两者只是输出目标的不同:前者是显示器(如果是内存位图也一样);后者是PS文件.这样就很容易实现WYSISYG——只要将坐标单位设置为英寸(或英寸的千分之一)就行了.这里介绍一个技巧,由于汉字的打印是通过打点实现的,所以这样会使得PS文件比较大.要减小PS文件,可以将连续的打点用画线来代替.由于打印机的分辨率很高,这样做的效果会很明显:一般可以将PS文件减小到原来的1/5,这将大大减少写打印机端口的时间. 4、结束语 在VxWorks中使用TrueType字库的方法已成功地应用于Vxworks嵌人式地理信息系统中,并可以很容易地移植到很多其他的系统中.
|