让s60支持svg显示吧

北京理工大学 20981 陈罡
svg图像格式(全称为Scalable Vector Graphics)。该技术早在2001年9月4日由w3c发布svg 1.0标准的时候就已经开始慢慢地成为矢量图形跨平台存储、显示的强大工具了,在这里我就不再重复svg的特点——从它的名字就可以看出来,最大的特点就是矢量图形,可以支持无级缩放、旋转而不会导致图像质量的下降(还是重复了。。。汗)。
与adobe公司的flash相比,既有不如人家的地方(例如,不支持变形,不支持强大的编辑器等等,人机交互也支持得有限),也有比flash强大的地方(偶个人认为,简单就是强大的另一种表现形式)。到了2003年1月14日,w3c又发布了SVGT(全称为Scalable Vector Graphics,Tiny Profile,可以翻译为可缩放的矢量图形标准的微型简化版本)和SVGB(全称为Scalable Vector Graphics, Basic Profile,可缩放的矢量图形标准的基本版)。从宏观上来说,svgt和svgb都是svg标准的子集,都是考虑到手持和便携式设备有限的内存、cpu处理速度而引入的高度精简版的svg标准。尽管w3c已经非常努力地划分了svgt和svgb的使用范围,例如他们认为svgt可以用于手机等手持设备,svgb可以用于pda等掌上电脑设备,可是那毕竟是“学院派”的做法,随着智能手机的不断发展,手机的运算能力和处理速度已经远非这些“学院派”的专家们所能想像的了。以目前的发展趋势来看,手机上支持完全版的svg也不是不可能的事情,相对png,jpeg或者flash来说可能svg要稍微慢一点罢了。目前,svg标准的最新版本(还没有出来的版本)为1.2。
目前对于svg标准的支持在浏览器领域已经非常广泛了,主流的浏览器如firefox, opera, mozilla等等都已经可以堪称“完美”。但在手机和PDA上面,可能手机毕竟是硬件制造厂商吧,对于这种新标准的跟进还是持有审慎态度的。目前symbian s60 3rd上已经在使用svgt的标准了(例如程序图标就采用了svg格式,在程序中可以利用mif,或者mbm等与编译出来的包静态地使用svg图片资源),win mobile偶还没怎么听说,不过相信微软在跟进的动作上也不会落后的。但是很遗憾nokia或者symbian还没有开放可以直接读取和解析svgt的接口(如果我说得不对,请各位大侠不吝斧正!)。于是,有必要自己做一些尝试,看看能否借助于open source的力量在手机上实现svg图片显示方面的支持。
借助于google,我找到了如下的几个支持svg的library:
(1)librsvg
目前已经发展到2.13,而且很早就已经成为大家所熟知的gnome桌面环境的一部分,得到了广泛的使用,它依赖于libxml2以及libart这两个library。librsvg可能是目前既支持svg标准又open source的最强大的库,当然移植起来也会让人为它的强大付出代价。
(2)cairo
它是linux领域的大哥大级别的库了,过去叫做Xr或Xr/Xc,是一个跨平台的开放源代码的矢量图形函数库。Cairo提供一个稳定的用户层API,它可以提供现代化的图形处理管理能力,如绘制和填充,映射转换,合成(注意,是合成)与改变alpha半透明图像,高真文本显示等等。能够在不同的媒体上实现相同的输出。目前,open source的html解析引擎gecko将要使用cairo增强渲染速度以及改善文字显示效果。最新版本的cairo是支持svg输出和显示的。
(3)agg
一个强大的基于c++的2D图像显示、处理库,(偶个人的首选库,用起来很舒服)。如果仅仅从svg的角度来看的话,它是可以支持svg的,但是如同它的readme中强调的,只支持很弱的一部分svg的显示和解析。
(4)libsvg, libsvg-cairo
说道这两个库,不得不提起一位牛人Carl Worth,他本人也是cairo库的作者之一。自从有了librsvg项目以后,他就寻思着用librsvg来做svg图像的解码引擎,用cairo二维绘图库来进行前台的绘图和输出。于是他就抓取了一个可用的librsvg的源代码,然后首先把其改造成平台无关的库,这个库也就是libsvg库的由来,到现在为止,似乎这个libsvg已经不再有人继续维护它了,不过代码结构还是很清晰的。那么,有了libsvg库以后,总得有什么东西把libsvg与cairo连接起来啊,这就类似于c++模式里面的adapter,适配器一样,这个libsvg-cairo就是干这个用的。把libsvg跟cairo联系起来,用libsvg-cairo来调用。如果你单独看libsvg看不明白的话,可以借助于libsvg-cairo一起来看,就一切明了。由于libsvg本质上也是从librsvg衍生出来的,所以仍然需要libxml的支持,在实际的编译过程中,还要用到zlib(这是对svgz的压缩格式svg的支持),jpeglib, pnglib等常规的图像处理库。
经过一天的dig,总算可以基本上评估一下在s60 3rd上的工作量了,如果采用libsvg的话是完全有可能实现的,而且最新版本的libsvg已经不仅仅局限于libxml2做为xml的解析引擎了,而是已经实现了expat引擎的xml解析。结合symbian上面著名的syexpat开源项目,这个library的成功移植只是一个时间问题了。
很是郁闷,sourceforge最近上不去了,有人说是国家封锁,我不信,泱泱大国怎么可能封锁那种技术性的网站?后来查了一下,原来近期sourceforge是网站迁移,可能是国内的dns解析没有更新的缘故吧。通过代理是可以访问的。
顺便秀一下偶的原理性的实验:
希望能够对后来者有所帮助。
上一篇讲到目前可以很容易就找到的支持svg显示的几个库,像librsvg这个比较成熟的svg渲染库,
移植起来肯定难度不小,而且其本身是针对linux环境做的,对于手机或者其它嵌入式平台而言,
它本身认为理所当然系统应该具有的lib,在实际的环境中往往没有。这就更加增大了移植的难度。
偶个人认为最好从最直接能够解决问题的库入手,于是就选中了libsvg这个库。以下的全部工作
都是围绕着libsvg这个库的编译、使用展开的。而且,很不幸,libsvg库也是基于librsvg的一个
移植,因此,它也是要依赖于其它的lib的。好在,依赖的不多,主要有libexpat或者libxml2,
以及libpng, libjpeg, zlib。
大概的浏览了以下libsvg的代码,普通的svg格式肯定都没有问题(这一点明显要强于svgt和svgb)。
从svg_image.c来看,这个版本的libsvg是假定svg中的图片都是“引用”得svg文件外部的图片的,
目前可以支持的格式为jpeg和png。偶看到较新的svg文件一般都可以将jpeg或png用base64编码,
做为svg文件中的内嵌的图像数据,这样显然要比外部引用要好一些,至少一个svg把自己需要的资源
全都“自包含”了。当然可能很多人会有不同的意见,主要是svg的xlink可以引用远程的其它主机的
资源。这一点当然很好,不过目前我们的目标是在手机平台上能够运行,所以要尽量避免一下“远程”
这个概念,这会导致联网,以及糟糕的用户体验。
另外,在svg.h中,libsvg定义了一个硕大的结构体:

typedef struct svg_render_engine

这个所谓的svg_render_engine就是一个包含着多个指向函数的指针的结构体,由于整个libsvg
是采用纯c语言编写的,因此,想要实现“OO”编程不得不借助大量的包含指向函数的指针的结构体。
这里的svg_render_engine就充当了这样一个角色,结构体中的每个指向函数的指针就相当于c++
语言中的“纯虚函数”。整个libsvg就是利用这些“纯虚函数”完成所有的svg数据操作和显示的,当然
前提是在我们使用这个lib的时候,已经自己实现了这些“纯虚函数”。整个libsvg其实就是一个svg
文件的“渲染引擎”,它留出来了绘图函数、以及坐标变换的接口函数(就是这个svg_render_engine),
等着libsvg库的调用者来实现具体的操作函数。我想,这就是libsvg的核心思想了,让“渲染引擎”与
具体的实现的绘图、坐标变换等平台相关函数分开,做到平台独立。这样就可以很方便地将libsvg
移植到各种嵌入式或者pc的平台上面去了。
libsvg的作者的思路是很好的,这一点相比librsvg而言已经进步了一大步,但是作者还需要考虑一点
的是——大多数开发者还是很难看明白他的良苦用心,毕竟是30多个函数啊,而且里面还有各种矩阵变换,
图形缩放、坐标变换平移、字体操作等等。这些东西实现起来并非易事。单就xml解析器而言,就很麻烦,
幸好现在最新版本的libsvg已经可以同时支持libexpat和libxml2两个库了。对于symbian手机平台而言,
已经有国外的大侠们移植的syexpat这个库了。相对还是比较容易一些,于是就采用libexpat做为libsvg
库的xml解析器了(syexpat是将expat库移植到symbian上之后,又用c++给expat api做了一个wrapper,
这个wrapper虽然很好用,但是libsvg是采用没有wrapper的expat api的,呵呵,所以需要手工把syexpat
修改一下,让它支持如XML_Parser,XML_SetStartElementHandler之类的调用方式)。
移植的时候可以先关注svg_parser.c和svg_parser_expat.c这两个文件。偶个人建议,如果不打算让移植
的库支持不同的xml解析器的话,最好把这两个文件给合并起来,成为一个文件。这样会免去编译时候的
很多问题。然后就是关于zlib、libpng、libjpeg这几个了,从代码上来看,libsvg还是使用了zlib的api
函数的,主要是在svg_parse_file, svg_parse,这里需要说明一点的是,zlib中有几个关于打开文件的
api,叫做gzopen()和gzdopen(),这里面还有点让人郁闷的东西,就是gzdopen()这个函数。在linux
环境中,是可以通过dup()函数来复制一个文件的句柄id的,然后通过文件的id号(或句柄号)来打开这个
文件,但是在手机或者嵌入式平台,这一招就有可能不适用。因此,还是建议将gzdopen都换成gzopen()
利用传入的文件名来打开文件。
好了,有了这些再加上心细一些。肯定能够成功地将libsvg移植到win32上去(有朋友可能会问,为什么要
移植到win32上?不是要移植到手机上吗?呵呵,主要原因是win32的调试和编译比较快,在移植的前期问题
多多的时候,先在win32上移植,效率要比直接上手机开发环境移植高得多,而且单步调试之类的工具也是
非常丰富)。这些移植好之后,就会发现,我们已经把libsvg这个渲染引擎移植到pc上了(偶目前也成功地
将其移植到手机上了,效果很令人满意),但还不能够做任何事情——我们还没有实现svg_render_engine中
定义的那些“纯虚函数”(其实就是指向函数的指针了,那些指针所指向的函数是需要我们自己去实现的)。
大概看了一下,简单的move_to,line_to之类的简直轻而易举。但复杂一些的,如文字类型、大小、字体处理
坐标变换之类的,实现起来就很麻烦。于是就有了在《让s60支持svg显示吧-(1)》文章最后,展示的那张
图片,只实现了move_to,line_to函数的libsvg渲染引擎的效果图——只用线条绘制出来的svg图形。但是这样
的效果是远远不够的。
为了达到perfect的效果,我们有必要继续移植一个“完全”的libsvg渲染引擎的实现函数,于是目光转向了
libsvg-cairo这个库。该库是基于libcairo 2d绘图库实现的libsvg引擎的应用库。值得一提的是,该库的
作者就是libsvg的作者,呵呵,想必作者实现了libsvg库以后,一时技痒就依赖于cairo把libsvg的调用库
也顺手写出来了。这对我们来说可是一个天大的好消息,毕竟不用自己去处理那么复杂的坐标变换之类的移植
工作了。libsvg-cairo本身也就五、六个文件而已,移植起来易如反掌,在此不再赘述了。
移植完libsvg和libsvg-cairo以后,随之而来的是cairo这个二维绘图库的问题(当时偶是欲哭无泪)。可以
肯定,手机上是绝对不会有cairo这个库的,如果想在手机上使用libsvg-cairo,就必须要自己动手去移植
cairo库。于是乎,新的一轮dig又开始了。很快就会发现,这个cairo号称支持xlib,pdf,png,svg,win32,xcb多种平台和格式的文件输出,又是一个“大块头”。
这时候,有两条路摆在面前:
(1)放弃移植libcairo,转而仔细阅读libsvg-cairo的实现代码,自己实现libsvg的svg_render_engine。
(2)咬牙硬啃libcairo,将其不必要的win32, xlib等等相关的代码去掉,只把运算和内存渲染图片部分代码
保留并移植出来。
偶是个懒人,不喜欢动脑筋(没办法,睡觉要紧啊!),所以决定采用方案(2)。很快在cairo的关于内存
图片操作的函数中(主要是cairo_image_surface_xxxxx系列函数)发现cairo竟然大量使用了pixman这个库,
shit,又多了一个库,意味着又多了工作量。。。偶怎么这么命苦啊。。。于是转过头来看pixman这个库都有
啥特殊的功能,不看还好,一看就看到了很多诸如mmx之类的让人头大的东西。这些东西在win32和linux等基于
pc硬件的系统中都是可以大大加快处理速度的,但是对于嵌入式设备来说,多数arm芯片都不支持这些东西。
越靠近底层,越为移植制造麻烦。看了一下libcairo的log,里面说pixman原本是属于libcairo的一个“工具”类
的共享库,后来越做越完善,最终独立出去成为一套底层面向pixel,pixbuf,这个级别的图像操作库。呵呵,
换句话来说,早期的libcairo应该包含了这个pixman的库才对。赶紧回头去看看libsvg-cairo库的readme,发现
libsvg-cairo是track到libcairo 0.5.0的,也就是说0.5.0这么低的版本的cairo都可以完成libsvg-cairo的
绘图要求。呵呵,心中暗喜。然后马上找libcairo的低版本的代码,鉴于sourceforge还无法正常访问,所以
只好找到哪个算哪个了。
于是,找到了libcairo 1.0.0虽然版本高了一点,但毕竟也是相对最新的1.6.x而言
还是比较“老”的。打开一看,果然,pixman是直接包含在libcairo的库代码里面的。
好了,这下可以放心一些了,只要把pixman关于pixman_image_xxx的函数提取出来移植即可。这里需要说明
的是在pixman的代码目录里面有一个叫做pixman_remap.h的函数,天知道这东西是干嘛使的,把大多数的
pixman_xxxxx的函数都改名为_cairo_xxxxx。可能对于这个版本的作者来说,他自己实现了一组底层操作函数,
在没有确定pixman库完全可用之前,尽管在代码中写着是调用了pixman的库,但实际上还是调用自己的cairo
库中的函数,可能为以后移植或者将pixman全面引入创造条件吧。总之,这个remap,偶是不需要的,直接剔除
之,然后就是cairo的移植了。可以先加入少量文件,然后根据编译的错误逐渐添加缺失的文件。去掉字体相关
的代码和engine(这是为了尽量少跟freetype之类的打交道,要不又要增加工作量了,不过对于字体的处理,逃
估计是逃不过的,早晚要面对)。
呵呵,初次编译会有1800多个error,只要耐心一些都能够一一解决。
这里值得特别注意的是cairo的surface大爷的竟然不提供诸如surface->data或者cairo_image_surface_get_data()
之类的函数,那样的话,即使svg_cairo_render()函数将svg图像画入surface以后,也弄不出来,不能一个像素
一个像素的绘制到屏幕上去。于是,这部分需要自己动手,把surface中的二进制数据提取出来,然后进行绘制,
这一步操作可以通过跟踪cairo-png.c的实现过程得到想要的二进制数据。
最后就是久违了的成功!!
抓图秀一下结果,呵呵,熟悉svg的朋友一定对这个经典的老虎记忆犹新吧:


有了这些经验,将其在手机上跑起来,只是一个时间上的问题而已。
困了,睡了。。。

今天整整用了一下午的时间,总算让libsvg, libsvg-cairo, libcairo, libpixman
等库可以流畅地在symbian s60模拟器上运行了。

这里需要说明一下的是,关于libsvg中使用的xml解析器。它可以使用expat解析器和libxml2的解析器,
对于symbian而言,我们可以很容易的拿到syexpat的源代码。但是能不能直接用在这里呢?答案是否定的。
syexpat虽然做得已经很好了,但毕竟是对原有expat库进行了基于c++类的封装。而目前在libsvg中所采用
的expat是“原汁原味”的。所以还需要做一点修改了,具体的过程很简单,就是要把作者封装了的类去掉,
然后使用expat原本的api函数即可。这里需要特别注意一点的是,syexpat的作者移植expat库的时候,由于考虑到symbian本身内建的字符处理系统是基于unicode的,因此,他把syexpat的配置进行了少许修改,
让expat传递给解析函数的变量字符串都是采用unicode进行编码的。但是做为svg解码器而言,是不需要这个变换的,所以我们需要找到expat_config.h文件,找到如下编译开关:
#define XML_UNICODE
#define XML_UNICODE_WCHAR_T 1
可以把它修改成为:
#undef XML_UNICODE
#undef XML_UNICODE_WCHAR_T
呵呵,这个小bug折腾了我半天,我还纳闷expat怎么会自动支持unicode呢?
模拟器抓图如下:
这张是经过了缩放和旋转以后的老虎图:
这张也是很著名的小狮子:
下班了。。。困死了。。。
最后,贴上一个sis包,请注意,这个是为s60 3rd平台开发的demo程序。需要经过签名才可以安装到手机
上。
sis包(需要自己做sign才能安装,安装路径不限)
文件:SvgMap.rar
大小:347KB
下载:下载
使用方法:
(1)选择open,在弹出对话框里面选择svg文件,如果没有错误的话,就会全屏显示
(2)数字键“1”代表放大;数字键“2”代表缩小;每次缩放,步长为10个像素
(3)支持如下格式的外部链接图片:
<image width="100" height="100" xlink:href="pengui.jpg" transform="matrix(0.2095 0 0 0.1836 0.4575 31.3215)">
但是要求xlink的图片必需要与svg文件在相同的目录下。另外,xlink的图片最好不要过大,会造成内存
分配失败。
(4)查看完毕后,选择"close"菜单项即可(其实不选择也没关系,这里是做资源释放实验用的)
目前还在做的工作是:
(1)加入旋转功能,旋转后图片是相对左上角坐标(0,0)旋转的,因此,图片定位比较麻烦。
(2)加入对字体轮廓的渲染功能,这一点是在svgt中有所定义的,illustrator中也用这种方式
输出文字,不过要想在symbian上实现这种效果,最好借助于freetype来实现。因此,基于freetype
的backend还在开发中。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值