Python Django PDF Сведение полей формы

У меня есть проект, в котором мне нужно заполнить предварительно созданные PDF-файлы, и наиболее логичное решение, которое приходит на ум, состоит в том, чтобы преобразовать предварительно созданные PDF-файлы в PDF-формы, чтобы были теги, в которые должны входить входные значения, а затем Я могу просмотреть теги формы в PDF и сопоставить их со словарем значений.

Я сделал это, используя PyPDF2. В целом, я взял изображение веб-формы, а затем открыл Acrobat и создал форму PDF на основе полей, видимых на изображении, затем использовал PyPDF2 для заполнения полей формы PDF, но предостережение в том, что печать заполненных значений кажется глючит в некоторых браузерах, одним из которых является Firefox.

Как мне преобразовать мою PDF-форму в стандартный/плоский PDF, чтобы я мог сохранить предварительно заполненные значения, но потерять редактируемые поля (поскольку я думаю, что это проблема)?

from io import BytesIO

import PyPDF2
from django.http import HttpResponse

from PyPDF2.generic import BooleanObject, NameObject, IndirectObject


def pdf_view(request):
    template = 'templates/template.pdf'

    outfile = "templates/test.pdf"

    input_stream = open(template, "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 = {
        'first_name': 'John',
        'last_name': 'Smith',
        'email': '[email protected]',
        'phone': '889-998-9967',
        'company': 'Amazing Inc.',
        'job_title': 'Dev',
        'street': '123 Main Way',
        'city': 'Johannesburg',
        'state': 'New Mexico',
        'zip': 96705,
        'country': 'USA',
        'topic': 'Who cares...'

    }

    pdf_writer.addPage(pdf_reader.getPage(0))
    pdf_writer.updatePageFormFieldValues(pdf_writer.getPage(0), data_dict)

    output_stream = BytesIO()
    pdf_writer.write(output_stream)

    # print(fill_in_pdf(template, data_dict).getvalue())

    # fill_in_pdf(template, data_dict).getvalue()
    response = HttpResponse(output_stream.getvalue(), content_type='application/pdf')
    response['Content-Disposition'] = 'inline; filename = "completed.pdf"'
    input_stream.close()

    return response


def set_need_appearances_writer(writer):
    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
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
3
0
3 089
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Решение было очень простым, прочитайте документы, если сомневаетесь (стр. 552/978):

https://www.adobe.com/content/dam/acom/en/devnet/pdf/pdfs/pdf_reference_archives/PDFReference.pdf

Все, что мне нужно было сделать, это изменить битовую позицию флагов поля на 1, сделав поле только для чтения, например:

from io import BytesIO

import PyPDF2
from django.http import HttpResponse

from PyPDF2.generic import BooleanObject, NameObject, IndirectObject, NumberObject


def pdf(request):
    template = 'templates/template.pdf'

    outfile = "templates/test.pdf"

    input_stream = open(template, "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 = {
        'first_name': 'John\n',
        'last_name': 'Smith\n',
        'email': '[email protected]\n',
        'phone': '889-998-9967\n',
        'company': 'Amazing Inc.\n',
        'job_title': 'Dev\n',
        'street': '123 Main Way\n',
        'city': 'Johannesburg\n',
        'state': 'New Mexico\n',
        'zip': 96705,
        'country': 'USA\n',
        'topic': 'Who cares...\n'

    }

    pdf_writer.addPage(pdf_reader.getPage(0))
    page = pdf_writer.getPage(0)
    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:
            # -----------------------------------------------------BOOYAH!
            if writer_annot.get('/T') == field:
                writer_annot.update({
                    NameObject("/Ff"): NumberObject(1)
                })
             # -----------------------------------------------------
    output_stream = BytesIO()
    pdf_writer.write(output_stream)

    response = HttpResponse(output_stream.getvalue(), content_type='application/pdf')
    response['Content-Disposition'] = 'inline; filename = "completed.pdf"'
    input_stream.close()

    return response


def set_need_appearances_writer(writer):
    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  

Великолепная детективная работа в совершенно скучной документации. Знаете ли вы, можно ли это вообще применить ко всем типам полей? В настоящее время у меня есть флажки и текстовые поля, и я не могу отключить флажки.

markwalker_ 18.02.2020 19:51

@markwalker_, к сожалению, я не смог заставить флажки работать так же, как текстовые поля, в итоге я создал текстовые поля для «флажков», а затем отрендерил «X» сверху и сгладил его.

ViaTech 18.02.2020 20:10

Другие вопросы по теме