Android阅读器开发相关资料(上-pdf)
2011-12-24 08:37 onm 阅读(318) 评论(0) 编辑 收藏 举报最近研究了一下Android上pdf阅读应用和纯文本阅读应用的相关东西。
先说pdf阅读器,这个网上开源的东西比较多,解析pdf都是用的现成的库,这种库有很多,有java实现的,有c实现的。一搜一大堆,看过能有七八个开源的pdf阅读器,java实现的都巨慢无比,全都舍弃,c实现的速度还可以,看到用的最多的c库是mupdf,主要是通过jni调用。但是要优化好那是相当不容易了。另外,这些库都相对比较大。
我参看了很多Market上的pdf阅读应用,感觉Adobe Reader做的帅呆了,以前没觉得帅,主要是要研究优化,看到了很多以前没看到的技术上的细节,Adobe Reader优化做的相当好。
其实pdf渲染机制,和浏览器渲染网页有很多相似的东西,一些优化手段是相同的,Android 4.0上的浏览器看着特别明显。
那么就说下pdf渲染机制,我看到的大部分实现,其实最终渲染的是一张一张图片(Adobe Reader还可以选择文字,添加书签,这简直酷爆了,不知道怎么做的)。过程是,
先定位视口对于文档的相对位置,然后根据pdf解析库,得到相应位置,相应缩放比例的pdf的位图,然后再把这个位图用canvas绘制到屏幕上。这是最简单的渲染机制,复杂的地方在于,页的切换和页面的放大缩小。
我们知道,由于手机设备内存小,一个Android应用只有很小的堆栈内存分配,如果你不做任何处理,只是翻一页生成一个图片,放大缩小重新生成一个图片,那么很快就会oom,内存溢出。这点可以看出,pdf的渲染机制,其实转化成了很多图片切换缩放的优化处理。所以如何回收内存,何时回收内存是个大问题。
我的目标交互是,页连续竖直紧挨排列,然后竖直滑动浏览。可以多点缩放大小,放大后,可以左右滑动位置。(类似于Adobe Reader)
当用户上下滑动到某个位置的时候,通过jni调用生成图片(有个延迟),然后该可视范围内的图片生成重绘出来,当再次滑动到了新的位置时,为了防止内存溢出,应当回收之前的图片,但是这样的问题就是,当用户在回到刚才的位置时,由于图片回收了,所以显示的是空白,这样体验很不好。通关观察一些应用和开源实现,我总结发现,滑动回刚才的位置时应该首先加载了原来位置处的缩略图(之前要缓存),然后再加载正确比例的图片,这样,视觉上看起来就好很多,可以大概看到那个位置的东西,这样的感觉就是很快。
然后是缩放,放大或者缩小都需要通过jni重新生成这确比例的位图,然后重新渲染,这样也存在那个问题。其实渲染的过程仔细看,可以看出渲染应该是分块渲染的,不是整屏的位置都一起渲染一个大图,而是等分成按比例的若干个块,然后一个块一个块的分块加载。这样的话,放大好弄一点,放大时,以放大中心位置所在的那个块放大,显示缩放原始的这样位图,所以当发大后会有点虚,然后放大结束后才真正渲染正确比例的位图。然后回收周围那些看不到的位图,这样问题就来了,当再缩小时,周边的图由于被回收了,所以变成了空白,这点Android4.0原生浏览器特别明显,其实还是可以优化的,Adobe Reader是这样做的,周围的图片缓存了缩略图,当缩小的时候,周围的图会迅速渲染上缩略图,看着有点模糊,但是比起空白好多了,所以这样,效果就相当赞了。
总结一下就是,分块加载,缓存缩略图,动态生成真实比例的位图,及时回收位图。这里面其实涉及到大量细节,实现起来相当复杂。
另外,基于c的开源实现的pdf阅读器,基本上都用了mupdf这个库,并且mupdf这个库自带了一个Android的简单demo,没有做任何优化处理,只是一页一页的显示。另外,Android 4.0的原生浏览器很顺滑,可以看出做了很多优化,当然这里面缓存,分块,回收,生成的时机相当重要,也很复杂,是最大的难点。
一些相关连接:
一些开源的pdf查看器:(还有一些,链接已经不记得了)
http://code.google.com/p/apv/
http://code.google.com/p/droidreader/
http://code.google.com/p/vudroid/
http://code.google.com/p/ebookdroid/ (优化的最好的,实现了我文中所说的大部分优化)