日志记录#
从版本 1.19.0 开始,更新 PDF 文档时支持日志记录功能。
日志记录是一种日志机制,允许对 PDF 文档的更改进行撤销或重新应用。类似于现代数据库系统中的 LUW(“逻辑工作单元”),可以将一组更新操作组合成一个“操作”。在 MuPDF 的日志记录功能中,一个操作扮演着 LUW 的角色。
注意
与数据库系统中的 LUW 实现不同的是,MuPDF 的日志记录功能发生在文档级别。不支持同时更新多个 PDF 文档:需要在此处建立自己的逻辑。
必须通过文档方法来启用日志记录功能。对于现有文档或新文档,日志记录功能都是可用的。只能通过关闭文件来禁用日志记录功能。
一旦启用,所有更改都必须在一个操作内部进行,否则将引发异常。操作通过文档方法启动和停止。在这两个调用之间发生的更新组成一个 LUW,因此可以集体回滚或重新应用,或者,在 MuPDF 术语中称为“撤销”和“重做”。
在任何时候,可以查询日志记录状态:日志记录是否启用、已记录了多少个操作、是否可以“撤销”或“重做”、当前在日志中的位置等等。
日志可以保存到文件或从文件加载。这些都是文档方法。
加载日志文件时,会检查与文档的兼容性,并在成功时自动启用日志记录功能。
对于正在进行日志记录的现有 PDF 文档,提供了一个特殊的新保存方法:
Document.save_snapshot()
。这会执行一个特殊的增量保存,其中包括到目前为止的所有日志记录的更新。如果其日志文件同时保存(紧随文档快照之后),那么文档和日志就是同步的,之后可以一起用于撤销或重做操作,或继续进行日志记录的更新 – 就如同没有中断发生一样。快照 PDF 在各方面都是有效的 PDF 文档,且完全可用。然而,如果文档在不使用其日志文件的情况下以任何方式发生更改,就会发生不同步,并且日志文件将无法使用。
快照文件的结构类似于增量更新。然而,内部日志记录逻辑要求,保存操作必须发生在新文件中。因此用户应制定文件命名约定,以支持原始 PDF(例如
original.pdf
)与其快照集(例如original-snap1.pdf
/original-snap1.log
、original-snap2.pdf
/original-snap2.log
等)之间可识别的关系。
示例会话 1#
描述
创建一个新的 PDF 并启用日志记录功能。然后添加一个页面和一些文本行 – 每一项都作为一个独立的操作。
在日志中导航,撤销和重做这些更新,并显示状态和文件结果
>>> import pymupdf >>> doc=pymupdf.open() >>> doc.journal_enable() >>> # try update without an operation: >>> page = doc.new_page() mupdf: No journalling operation started ... omitted lines RuntimeError: No journalling operation started >>> doc.journal_start_op("op1") >>> page = doc.new_page() >>> doc.journal_stop_op() >>> doc.journal_start_op("op2") >>> page.insert_text((100,100), "Line 1") >>> doc.journal_stop_op() >>> doc.journal_start_op("op3") >>> page.insert_text((100,120), "Line 2") >>> doc.journal_stop_op() >>> doc.journal_start_op("op4") >>> page.insert_text((100,140), "Line 3") >>> doc.journal_stop_op() >>> # show position in journal >>> doc.journal_position() (4, 4) >>> # 4 operations recorded - positioned at bottom >>> # what can we do? >>> doc.journal_can_do() {'undo': True, 'redo': False} >>> # currently only undos are possible. Print page content: >>> print(page.get_text()) Line 1 Line 2 Line 3 >>> # undo last insert: >>> doc.journal_undo() >>> # show combined status again: >>> doc.journal_position();doc.journal_can_do() (3, 4) {'undo': True, 'redo': True} >>> print(page.get_text()) Line 1 Line 2 >>> # our position is now second to last >>> # last text insertion was reverted >>> # but we can redo / move forward as well: >>> doc.journal_redo() >>> # our combined status: >>> doc.journal_position();doc.journal_can_do() (4, 4) {'undo': True, 'redo': False} >>> print(page.get_text()) Line 1 Line 2 Line 3 >>> # line 3 has appeared again!
示例会话 2#
描述
类似于上一个,但在撤销了一些操作之后,我们现在添加了一个不同的更新。这将导致
已撤销的日志条目被永久移除
新的更新操作将成为新的最后一个条目。
>>> doc=pymupdf.open() >>> doc.journal_enable() >>> doc.journal_start_op("Page insert") >>> page=doc.new_page() >>> doc.journal_stop_op() >>> for i in range(5): doc.journal_start_op("insert-%i" % i) page.insert_text((100, 100 + 20*i), "text line %i" %i) doc.journal_stop_op()
>>> # combined status info: >>> doc.journal_position();doc.journal_can_do() (6, 6) {'undo': True, 'redo': False}
>>> for i in range(3): # revert last three operations doc.journal_undo() >>> doc.journal_position();doc.journal_can_do() (3, 6) {'undo': True, 'redo': True}
>>> # now do a different update: >>> doc.journal_start_op("Draw some line") >>> page.draw_line((100,150), (300,150)) Point(300.0, 150.0) >>> doc.journal_stop_op() >>> doc.journal_position();doc.journal_can_do() (4, 4) {'undo': True, 'redo': False}
>>> # this has changed the journal: >>> # previous last 3 text line operations were removed, and >>> # we have only 4 operations: drawing the line is the new last one