编辑/高亮显示PDF在此脚本下变得太大.可以改进吗?



几年前我问过这个问题。我想从MyClippings.txt文件中提取我的Kindle注释,并用它们来注释原始文本的PDF版本。对于学术阅读非常有用(例如,带注释的原始PDF对于略读和引用更有用)。几个月前,我在以下脚本中找到了一个解决方案。

import fitz
# the document to annotate
doc = fitz.open("text_to_highlight.pdf")
# the text to be marked
text_list = [
"first piece of text", 
"second piece of text",
"third piece of text"
]
for page in doc:
for text in text_list:
rl = page.search_for(text, quads = True)
page.add_highlight_annot(rl)
# save to a new PDF
doc.save("text_annotated.pdf")
然而,从那以后我发现了一个新的问题。在一本700页的书中,PDF输出变得难以置信的大(超过5亿)。(该脚本必须运行几次,因为同时使用所有注释会导致崩溃;这不一定是个问题,但它表明效率低下)。有没有一种方法——我猜是基于python的——可以防止这种低效的结果?

你的问题有几个未知数:

  1. 原始PDF有多大?Kbs吗?Mbs吗?
  2. 这本书是什么语言?
  3. 你添加了多少注释?
  4. 您的文本列表中项目的复杂性是多少?

要全面诊断您的问题,访问PDF和文本列表中的几个搜索项将是有用的。有可能你的文本搜索范围太广,可能需要使用blocks = page.getText("dict", flags=flags)["blocks"]或其他东西。

下面的代码可能会有帮助。

注意我使用了"三引号",因为您的文本列表可能会导致崩溃。该列表可能包含多行字符串和本身包含引号的字符串。

我也相信在你的文档保存函数中使用这些参数做一些内务管理是有益的:

  • 垃圾= 4,比;垃圾收集未使用的对象,压缩:data:xref表,合并重复的对象和流
  • = True缩小→放气未压缩的流
  • 清洁= True→清理和消毒内容流

import fitz
doc = fitz.open("text_to_highlight.pdf")
text_list = [
"""first piece of text""", 
"""second piece of text""",
"""third piece of text"""
]
try:
for page in doc:
for text in text_list:
rl = page.search_for(text, quads = True)
page.add_highlight_annot(rl[0])
print(f"Added {text} annots on page {page.number}.")
except Exception as e:
print(e)
finally:
doc.save("text_annotated.pdf", garbage=4, deflate=True, clean=True)

一种解释(在没有看到文件的情况下很难知道)是重复的注释在某种程度上复制了PDF文件中的对象。如果运行cpdf -squeeze in.pdf -o out.pdf,它将合并任何重复的对象。如果你不能提供该文件,请务必发布cpdf的输出,它可能会提供有用的信息。

这里是cpdf二进制文件和Python文档的参考链接。

所以,如果有人来到这里,对这个功能感兴趣,让我分享一下工作流程和代码(从上面的稍微改变/改进,但基本上是一样的)。当你在ePub中阅读,但想将笔记保存在PDF中以便在做研究时更好地浏览时非常有用。

<标题>

目的使用Kindle生成的MyClippings.txt文件突出显示PDF。

<标题>

步骤首先,我们需要从myclipping中提取我们想要突出显示的PDF文本部分。相当简单的过程,手动完成。我们可以在original_long_lines.txt中保存(相当长的)行。

这是不够的:我们想把这些长行切成大约五个字的位(否则搜索PDF功能将无法正常工作)。为此,我们运行以下代码(检查input_fileoutput_file并相应地命名):

def break_lines(input_file, output_file):
with open(input_file, 'r') as file:
lines = file.readlines()
output_lines = []
for line in lines:
words = line.split()
if len(words) >= 3:
# Break line into new lines with a maximum of five words
for i in range(0, len(words), 5):
output_line = ' '.join(words[i:i+7])
output_lines.append(output_line)
with open(output_file, 'w') as file:
file.write('n'.join(output_lines))
print(f"Output written to: {output_file}")

# Example usage
input_file = 'original_long_lines.txt'
output_file = 'shorter_lines.txt'
break_lines(input_file, output_file)

其次,这也不够:你想剪掉只有一两个单词的行(以防止在PDF中一直突出显示这两个单词)。为此,我们使用以下代码:

def join_lines(input_file, output_file):
with open(input_file, 'r') as file:
lines = file.readlines()
output_lines = []
prev_line = ''
for line in lines:
words = line.split()
if len(words) <= 2:
prev_line += ' ' + line.strip()
else:
output_lines.append(prev_line.strip())
prev_line = line.strip()
# Add the last line to the output
output_lines.append(prev_line.strip())
with open(output_file, 'w') as file:
file.write('n'.join(output_lines))
print(f"Output written to: {output_file}")

# Example usage
input_file = 'shorter_lines.txt'
output_file = 'shorter_lines_no_one_or_two_words.txt'
join_lines(input_file, output_file)

最后,我们使用以下代码突出显示使用shorter_lines_no_one_or_two_words.txt文本文件的PDF。

import PyPDF2
import fitz
from tqdm import tqdm
def highlight_pdf(pdf_path, text_file):
# Load the list of strings from the text file
with open(text_file, 'r') as file:
search_strings = file.read().splitlines()
# Open the PDF file
pdf = fitz.open(pdf_path)
# Initialize the progress bar
progress_bar = tqdm(total=len(pdf), unit='page')
for page_num in range(len(pdf)):
page = pdf[page_num]
for search_string in search_strings:
text_instances = page.search_for(search_string, quads=True)
for inst in text_instances:
# Highlight the found text
highlight = page.add_highlight_annot(inst)
# Update the progress bar after processing each page
progress_bar.update(1)
# Close the progress bar
progress_bar.close()
# Save the modified PDF
output_path = 'highlighted_' + pdf_path
pdf.save(output_path)
pdf.close()
print(f"Highlighted PDF saved as: {output_path}")

# Example usage
pdf_path = 'your_pdf.pdf'
text_file = 'shorter_lines_no_one_or_two_words.txt'
highlight_pdf(pdf_path, text_file)

根据我的经验,这有时会成倍地增加最终文件的大小,有时则不会。这个问题可以很容易地用上面John Whitington提到的cpdf来解决,就像cpdf -squeeze huge_pdf.pdf -o small_pdf.pdf一样。现在你的PDF中有你的Kindle亮点了。

试试这个

import fitz
# the document to annotate
doc = fitz.open("text_to_highlight.pdf")
# the text to be marked
text_list = [
"first piece of text", 
"second piece of text",
"third piece of text"
]
for page in doc:
for text in text_list:
rl = page.search_for(text, quads = True)
page.add_highlight_annot(rl)

doc.save("text_annotated.pdf")

最新更新