使用Python生成扁平化PDF
当我从任何源PDF打印PDF时,文件大小会减小,并删除表单中显示的文本框。简言之,它将文件展平。 这是我想要实现的行为 下面的代码使用另一个PDF作为源创建PDF(我要展平的PDF),它还编写了文本框表单 我可以得到一个没有文本框的PDF文件吗,把它展平?就像Adobe将PDF打印为PDF一样 我的另一个代码看起来像这样减去一些东西:使用Python生成扁平化PDF,python,pdf-generation,reportlab,pypdf,Python,Pdf Generation,Reportlab,Pypdf,当我从任何源PDF打印PDF时,文件大小会减小,并删除表单中显示的文本框。简言之,它将文件展平。 这是我想要实现的行为 下面的代码使用另一个PDF作为源创建PDF(我要展平的PDF),它还编写了文本框表单 我可以得到一个没有文本框的PDF文件吗,把它展平?就像Adobe将PDF打印为PDF一样 我的另一个代码看起来像这样减去一些东西: import os import StringIO from pyPdf import PdfFileWriter, PdfFileReader from rep
import os
import StringIO
from pyPdf import PdfFileWriter, PdfFileReader
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
directory = os.path.join(os.getcwd(), "source") # dir we are interested in
fif = [f for f in os.listdir(directory) if f[-3:] == 'pdf'] # get the PDFs
for i in fif:
packet = StringIO.StringIO()
can = canvas.Canvas(packet, pagesize=letter)
can.rotate(-90)
can.save()
packet.seek(0)
new_pdf = PdfFileReader(packet)
fname = os.path.join('source', i)
existing_pdf = PdfFileReader(file(fname, "rb"))
output = PdfFileWriter()
nump = existing_pdf.getNumPages()
page = existing_pdf.getPage(0)
for l in range(nump):
output.addPage(existing_pdf.getPage(l))
page.mergePage(new_pdf.getPage(0))
outputStream = file("out-"+i, "wb")
output.write(outputStream)
outputStream.close()
print fName + " written as", i
总结:我有一个pdf,我在其中添加一个文本框,覆盖信息并添加新信息,然后从该pdf打印一个pdf。文本框将不再可编辑或移动。我想自动化这个过程,但我尝试的一切仍然允许编辑该文本框。如果安装操作系统软件包是一个选项,那么您可以使用
pdftk
及其python包装器pypdftk
,如下所示:
import pypdftk
pypdftk.fill_form('filled.pdf', out_file='flattened.pdf', flatten=True)
sudo apt-get install pdftk
您还需要安装pdftk
软件包,在Ubuntu上可以这样做:
import pypdftk
pypdftk.fill_form('filled.pdf', out_file='flattened.pdf', flatten=True)
sudo apt-get install pdftk
可从PyPI下载pypdftk
库:
pip install pypdftk
我很难用pdfrw()将输入内容的表单展平,并发现我必须使用generate_fdf()添加额外的步骤
我之所以选择这个解决方案,是因为我能够在Mac上使用ghostscript的PDF2P和ps2pdf将文件展平,但当我在Amazon Linux实例上运行它时,质量很低。我不明白为什么会出现这种情况,因此转移到pdftk解决方案。根据Adobe文档,您可以将可编辑表单字段的位位置更改为1,使字段成为只读字段。我在这里提供了完整的解决方案,但它使用Django: Adobe文档(第552页): 使用PyPDF2填充字段,然后循环注释以更改位位置:
from io import BytesIO
import PyPDF2
from PyPDF2.generic import BooleanObject, NameObject, IndirectObject, NumberObject
# open the pdf
input_stream = open("YourPDF.pdf", "rb")
pdf_reader = PyPDF2.PdfFileReader(input_stream, strict=False)
if "/AcroForm" in pdf_reader.trailer["/Root"]:
pdf_reader.trailer["/Root"]["/AcroForm"].update(
{NameObject("/NeedAppearances"): BooleanObject(True)})
pdf_writer = PyPDF2.PdfFileWriter()
set_need_appearances_writer(pdf_writer)
if "/AcroForm" in pdf_writer._root_object:
# Acro form is form field, set needs appearances to fix printing issues
pdf_writer._root_object["/AcroForm"].update(
{NameObject("/NeedAppearances"): BooleanObject(True)})
data_dict = dict() # this is a dict of your form values
pdf_writer.addPage(pdf_reader.getPage(0))
page = pdf_writer.getPage(0)
# update form fields
pdf_writer.updatePageFormFieldValues(page, data_dict)
for j in range(0, len(page['/Annots'])):
writer_annot = page['/Annots'][j].getObject()
for field in data_dict:
if writer_annot.get('/T') == field:
writer_annot.update({
NameObject("/Ff"): NumberObject(1) # make ReadOnly
})
output_stream = BytesIO()
pdf_writer.write(output_stream)
# output_stream is your flattened PDF
def set_need_appearances_writer(writer):
# basically used to ensured there are not
# overlapping form fields, which makes printing hard
try:
catalog = writer._root_object
# get the AcroForm tree and add "/NeedAppearances attribute
if "/AcroForm" not in catalog:
writer._root_object.update({
NameObject("/AcroForm"): IndirectObject(len(writer._objects), 0, writer)})
need_appearances = NameObject("/NeedAppearances")
writer._root_object["/AcroForm"][need_appearances] = BooleanObject(True)
except Exception as e:
print('set_need_appearances_writer() catch : ', repr(e))
return writer
一个同样适用于Windows的解决方案,可以转换许多pdf页面,并使chackbox值变平。由于某些原因,@ViaTech代码在我的电脑(Windows7 python 3.8)中不起作用 遵循@ViaTech指示,广泛使用@hchillon代码
一种简单但更全面的方法是将pdf转换为图像,而不是将这些图像转换为pdf 您需要pdf2image和PIL 像这样
from pdf2image import convert_from_path
from PIL import Image
images = convert_from_path('temp.pdf')
im1 = images[0]
images.pop(0)
pdf1_filename = "flattened.pdf"
im1.save(pdf1_filename, "PDF" ,resolution=100.0, save_all=True, append_images=images)
编辑:
我创建了一个名为fillpdf的库来执行此操作
pip安装fillpdf
from fillpdf import fillpdfs
fillpdfs.flatten_pdf('input.pdf', 'newflat.pdf')
也在寻找解决方案。我有一个带水印的Python脚本,但是当试图选择或突出显示文档中的文本时,水印会造成阻碍。如果我能生成一个平坦的水印PDF,然后将其与源PDF合并,那就可以解决它了。文件名是否遵循某种特定的约定?如果是,语义是什么?先按空格再按逗号拆分文件名的目的是什么?(否则,脚本将失败,但我不确定是否与您面临的问题相关。)我无法重现该问题。我没有箱子。你可以用你得到的结果和期望的结果粘贴一张图像吗?@gpoo我想这些盒子是存在于原件中的,但是我也不知道它是什么类型的盒子,我有一个pdf,第一页有一个盒子,但我无法通过打印将其删除(也许Acrobat Pro会这样做)@gpoo我当时想要的是:我有一个pdf,我在其中添加一个文本框,覆盖信息并添加新信息,然后从该pdf打印pdf。文本框将不再可编辑或移动。我想自动化这个过程,但我尝试的每一件事都允许文本框可以编辑。我希望这能把事情弄清楚。我使用的是Acrobat9.5,没有pdftk有什么方法可以做到吗?我之所以问这个问题,是因为我正试图编写一个pdftk克隆,因为pdftk在centos7上不起作用。任何帮助都将不胜感激。这在ubuntu 18.04上不起作用,因为
pdftk
不再在repo@FabrizioMiano我看到人们在这里讨论解决方法:qpdf也可能是一种替代方法。pdftk
可以作为pdf打印机使用,因此,cups
可能会起作用。我认为OP仍然希望保持页面内容的向量属性,而这个建议会将文档转换为(低分辨率)image?@AllanLRH Correct页面的矢量属性将丢失,并且会导致分辨率较低的图像,但图像仍然是完全可读的,并且可以在许多不同的情况下使用,其中可读性是唯一的要求。