为什么pdfjs的批注持久化比较困难?该怎样做才能实现批注的持久化?

413 阅读4分钟

一些朋友问我,说他们在使用pdfjs的时候,遇到了一个问题。就是在pdfjs中添加了批注之后,重新打开浏览器,批注就消失了。这是什么原因?又该怎么做,才能让pdfjs的批注持久化,保存到indexeddb或后端的服务器上去?

第一个问题相对来说比较简单,因为pdfjs的批注都是存在内存当中的,内存随着进程的启动而开始分配,随着进程的退出而释放。当用户关闭浏览器的时候,随着内存的释放,用户添加的批注也就自然而然消失了。

第二个问题则稍微复杂一点,而且没有什么简单的方法能够达成这个目标。想通过一两行代码或者某个API实现这个目标,也是不现实的。主要原因也比较简单,就是pdfjs的批注和用户行为耦合的比较深。当一个用户想要创建、编辑、删除一个批注的时候,他需要进行鼠标或键盘操作。这些操作会产生相应的事件,然后再由这些事件去驱动相关的代码,为用户创建批注。pdfjs没有为开发者预留相应的API能够直接操作批注。

如果我们想要持久化批注,那么我们需要在一个批注创建完毕后或者操作完毕后,保存这个批注的一些关键参数到数据库。但是关键就是如何处理这个“创建完毕”或者“操作完毕”。这里我们举两个简单的例子。比如说,当我们用画笔画一个批注的时候,我们需要等这个画笔画完并且确认之后,再提取相应的参数。又比如说当我们要移动一个文字标记的时候,在移动的过程中,不可能不停的去提取相应的参数保存到后台,而是应该等到移动结束后,进行一次单独的参数提取和保存。类似的,批注的操作过程中有很多个节点,而我们需要在一些批注创建、编辑、删除的节点上,保存我们相关的信息。但是这样的节点可能有十多个。因此想要实现一个较为完美的批注持久化,比较困难,需要逐个将这些节点找到,并调整其中的代码,以达成得到有效批注参数的目的。不过还有一种讨巧的办法,我们可以定时读取内存中已经存在的批注,将他们的参数提取出来保存到后台。这样既简单也省事。只是因为两次保存之间有间隔,因此有可能会因为这个延迟丢失少量批注。

完成对批注的持久化之后,我们还需要在PDF启动的时候,将这些持久化的批注重新渲染回页面上,这一点也同样不容易。如果我们不去调整pdfjs的代码,那按照pdfjs现有的逻辑,我们必须要能够模拟用户的鼠标和键盘操作,按照用户一开始操作的顺序逐个发送相应的事件,然后利用这些事件驱动pdfjs创建批注。这个实现起来比较困难,而且即使实现了,后期也难以维护。

如果想要达成这个目标,那么我们需要先将批注的创建过程和用户的鼠标键盘事件解耦开来。这两样东西一旦解耦解开来了,那么也就意味着我们不用通过鼠标操作,也能够使用api驱动相关的代码,让这些代码创建相应的批注。但是想通过解耦来达成目的,也并不简单,因为需要解耦的地方也有约十来处,我们需要逐个去修改,这并非是一件容易的事。

即使调整好批注创建的节点,解耦了所有需要解耦的地方,是否就能够实现pdfjs的持久化了?答案是——是的。但是并不意味着没有其它问题了。pdfjs中跟批注相关的点还有批注操作的前进、后退,PDF旋转时批注要跟着旋转,批注的复制等一系列的问题。通过上面提到的方法,实现了批注的持久化之后,可能还要考虑一下是否影响到了其它的功能。如果影响到了一些外围的功能,且这些外围的功能还是业务系统所需要的,那么还需要妥善的解决这些外围功能的问题。