尝试了一下使用Python来修改创建PDF文件。试用了PyPDF2、pdfrw这两个库之后还是前者提供的功能更丰富些,在这里记录下PyPDF2的简单使用。
方法
因为只是API接口的直接调用,也没什么可分析的,直接附上代码,
class Stripper(object):
def __init__(self, in_path, out_path, mark):
self.in_path = in_path
self.out_path = out_path
self.mark = mark
self.reader = None
self.writer = None
def execute(self):
with open(self.in_path, 'rb') as inputs:
self.reader = PdfFileReader(inputs)
self.writer = PdfFileWriter()
self.writer.cloneReaderDocumentRoot(self.reader)
total_nums = self.reader.getNumPages()
print 'total_nums', total_nums, self.in_path
for idx in xrange(total_nums):
page = self.reader.getPage(idx)
self.strip_annots(page)
self.strip_content(page)
with open(self.out_path, 'wb') as outputs:
self.writer.write(outputs)
outputs.flush()
def strip_annots(self, page):
annots = page['/Annots']
for link_info in list(annots):
obj_info = self.reader.getObject(link_info)
if '/A' not in obj_info:
continue
if self.mark in obj_info['/A'].get('/URI', ''):
annots.remove(link_info)
def strip_content(self, page):
contents = page['/Contents']
for content_info in list(contents):
content = self.reader.getObject(content_info)
if not hasattr(content, 'getData'):
continue
if self.mark not in content.getData():
continue
contents.remove(content_info)
上述 Stripper
类的功能是移除PDF中不想看到的某些内容,具体其实是移除来自it-ebooks.info加在页脚上的水印。大体步骤如下,
- 从
PdfFileReader
拷贝内容至PdfFileWriter
- 分析处理PDF每一页,对其中的内容进行相应的修改移除
- 将修改后的结果进行保存
PDF本身的格式没有花时间去了解,上述两个库的文档也都很简略。通过它们的示例能简单了解其功能,更具体的接口需要直接看代码。自己尝试的是用PyCharm断点跟踪来分析相应接口的用法与返回的数据结构。
问题
最先想使用PdfFileReader
的addPage
接口一页一页从PdfFileWriter
中进行添加,然后进行处理与输出。按照这个思路实现后先后遇到两个问题。
首先是导航书签的缺失,在分析相关接口之后实现了手动添加导航书签的方法,同时好像也发现了库的一出bug。虽然追后没采用这个方法,这里也权且记录一下,
def add_bookmarks(self):
self._add_bookmark_imp(self.reader.outlines, None)
def _add_bookmark_imp(self, destinations, parent=None):
bookmark = None
for destination in destinations:
if isinstance(destination, list):
self._add_bookmark_imp(destination, bookmark)
else:
page_num = self.reader.getDestinationPageNumber(destination)
title = unicode(destination.title)
bookmark = self.writer.addBookmark(title, page_num, parent)
PdfFileWriter
的addBookmark
存在bug,在标签名称包含unicode字符的情况输出的文件中会显示奇怪字符,对PyPDF2/pdf.py
需要修改713行,将,
dest = Destination(NameObject("/"+title + " bookmark"), pageRef, NameObject(fit), *zoomArgs)
修改为,
dest = Destination(createStringObject("/"+title + " bookmark"), pageRef, NameObject(fit), *zoomArgs)
另一个问题是内部跳转关系丢失。在分析代码之后,应当是可以通过PdfFileWriter
的addNamedDestinationObject
接口来手动创建的。但自己没找到正确的调用姿势,怎么添加在输出的文件中这个关系都还是建立的不正确。
最后还有一个问题是对某些PDF文件直接调用PdfFileReader
和PdfFileWriter
进行读写会报错,估计是库有问题。