Python Django PDF Achatamento de campos de formulário

Eu tenho um projeto onde eu preciso preencher PDFs pré-feitos e a solução mais lógica que vem à mente para conseguir isso é fazer os PDFs pré-criados em formulários PDF, então existem tags onde os valores de input devem ir, então Eu posso olhar através das tags de formulário no PDF e alinhá-las com um dictionary de valores.

Eu consegui isso usando PyPDF2 . No geral, tirei uma imagem de um formulário da Web e, em seguida, abri o Acrobat e criei um formulário PDF com base nos campos vistos na imagem, depois usei PyPDF2 para preencher os campos do formulário PDF, mas a impressão é que a impressão desses valores preenchidos parece buggy em alguns navegadores, sendo o Firefox um deles.

Como faço para converter meu PDF-Form em um PDF padrão / plano para que eu possa manter os valores pré-preenchidos, mas perder os campos editáveis ​​(como acho que esse é o problema)?

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': 'mail@mail.com', '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 

A solução foi super simples, leia os documentos quando em dúvida ( página 552/978 ):

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

Tudo o que eu precisava fazer era alterar a posição do bit dos sinalizadores de campo para 1, tornando o campo ReadOnly, da seguinte forma:

 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': 'mail@mail.com\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