抬头仰望星空,是否能发现自己的渺小。

伪斜杠青年

人们总是混淆了欲望和理想

如何开发一款Android PDF 编辑器

这半个月来,一直都在做 PDF 编辑,因为是公司项目,并不打算多说,但多少总结一下。毕竟从一开始毫无头绪,到现在成品已出,中间阻力还是不算小的。

免费的 PDF 编辑库

之前有调研过,直到目前做成,pdfium 已经被证明可以很好的实现常规的 pdf 操作,高亮、下划线、波浪线、手写、印章、文字等。

关于底层库的编译,移步:浅谈 Android pdfium.so 编译

我看到有人说无法编译成功,这里请确保网络通畅,并且请多尝试,我大概下了一整天加一晚上,完成后再更新就简单很多了。

中间层 JNI

关于 SO 库与 上层交互的部分,我是使用的:

https://github.com/benjinus/android-support-pdfium

主要原因是,首先他的代码比较新,其次JNI代码写得不错,很多方法,传参的方式等等都能用这个 demo 中得知。(如果又恰好不是那么懂 JNI 的话,这个可以说是刚刚好,模仿就完事儿了)

上层 PDF阅读

关于阅读以及编辑的基础,也就是底子,这里选的是:

https://github.com/barteksc/AndroidPdfViewer

我将其 PDF SDK具体实现逻辑改成了上面的 android-support-pdfium,也证明了这个库在抽象上做得也很好,大概花了1个小时左右,就完成了替换。

PDF 的编辑

AndroidPdfViewer 这个库代码比较清晰,逻辑没有那么复杂,做编辑则直接继承其阅读的 View 进行扩展即可。当然,这只是开始,另外还有两个难点:

  • 读懂渲染逻辑,做到编辑后实时渲染,笔记不闪烁。
  • 读懂坐标与缩放逻辑,完成 pdf 与屏幕坐标的转换。

关于坐标转换,这里是三层:

  • 具备缩放与位移的屏幕位置 => 原始的屏幕位置
  • 手机原始的屏幕位置 => PDF 原始的页面位置

不知道好不好理解,就是 缩放和位移后的屏幕坐标 => 不缩放也不位移的屏幕坐标 => PDF 页面本身的坐标。

一些坑

在PDF 中,有些很骚的操作,比如有一个 AP 模式。

简单说明:有一个获取 annot_color 的接口,如果不将 AP 模式置空,则无法获取颜色,但一旦将 AP 置空,则会导致 annot 中添加的对象 object 丢失(也就是前一秒通过 annot_get_object_count 获取到的是有对象,在经过 annot_get_color后就变成了0),如果恰好在遍历每个 annot 时都进行了 color 的获取,那么在擦除其中一个 annot 的时候,将会丢失所有 annot 的对象,也就是屏幕上将不会存在任何能看见的东西。

解决办法:对于 SDK 中定义好的28种 annot,均可通过设置 AP 来进行颜色获取。但对与需要 appendObject 的 annot,不要使用设置 AP 来进行颜色获取,而是使用 annot_get_object 再 get_object_stroke/fill_color 进行获取。

接口主要参考:fpdf_annot.hfpdf_edit.h

一些关系

PDF 每一页上面每个元素都是 pageObject。添加的批注 annot 实际上也是 pageObject,对于 TEXT,IMAGE,PATH,RECT,可以依附于 STAMP、INK 类型的 annot,也可以直接加入 page 中作为一个 pageObject。

对于每一个对象的操作,都是依赖于 page 的,对于各元素的获取,都是先获取 pageObejectCount 或者 pageAnnotCount 进行getByIndex遍历拿到的。

如果玩熟了,就会很简单,否则就是一头雾水。

其他问题

  • 一些类型比如 FREE_TEXT的正确使用方式 并不知道
  • 画笔的笔头实现(或许是多个 object 拼接而成,很是复杂)
  • 图像、音频、视频插入(实现方式未曾尝试)

主要参考实现

主要参考源码中的 TEST 用例:

https://pdfium.googlesource.com/pdfium/+/refs/heads/master/fpdfsdk/fpdf_annot_embeddertest.cpp

另外这里要特别感谢一位大佬以及他的项目,若不是他的逻辑让我看到了实现的可能,那我很可能没有勇气去做:

https://github.com/KnIfER/PolymPic

这个项目可以得到一些对于批注等操作的使用经验,比如文本传入底层需要追加”0″、文件的保存、又或者是编辑比如高亮等批注操作需要传入怎样的参数等等。另外,可以看这位大佬的博客:

https://www.jianshu.com/u/77921c0f8d4f

在这个项目中使用到的 API 应该有一百多个~ 很累。


0条评论

发表评论