使用Python生成扁平化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

当我从任何源PDF打印PDF时,文件大小会减小,并删除表单中显示的文本框。简言之,它将文件展平。 这是我想要实现的行为

下面的代码使用另一个PDF作为源创建PDF(我要展平的PDF),它还编写了文本框表单

我可以得到一个没有文本框的PDF文件吗,把它展平?就像Adobe将PDF打印为PDF一样

我的另一个代码看起来像这样减去一些东西:

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页面的矢量属性将丢失,并且会导致分辨率较低的图像,但图像仍然是完全可读的,并且可以在许多不同的情况下使用,其中可读性是唯一的要求。