Personal tools

Nov 18, 2011

Modulistica PDF online: popolamento automatico via Python

Un suggerimento per aggiungere testo a un file pdf comune, come ad esempio un banale modulo del censimento, utilizzando alcune delle librerie Python in circolazione

La creazione di pdf è spesso richiesta quando si sviluppa un'applicazione. Ma ci dobbiamo destreggiare in un mare di librerie Python

Per lo sviluppo di un'applicazione mi sono trovata a dover generare un pdf il cui contenuto consiste in un modulo, ad esempio il modulo del censimento, compilato con i dati degli utenti dell'applicazione presi run-time dal sistema.

Avrei impiegato troppo tempo a disegnare il modulo insieme ai dati dell'utente, in più, per certi moduli (come il modulo censimento) sono già forniti i pdf.

Pensare di caricare il modulo come immagine di sfondo non è fattibile. Prima di tutto per la qualità scarsa del pdf finale e poi perché le dimensioni del file di output aumentano molto a causa dell'immagine usata come sfondo.

Il file da ottenere è un modulo già fornito in versione pdf, ma a cui ho bisogno di aggiungere testo.

La soluzione, a mio avviso migliore, è stata quella di usare ReportLab per disegnare un pdf fatto unicamente dei dati dell'utente per poi fare un merge del primo con il pdf contente il modulo, usando PyPDF.

L'unica difficoltà in questo approccio è creare il pdf contenente i dati di riempimento. Infatti questi dati devono essere nella posizione giusta, prioprio come se stessimo compilando il modulo.

La soluzione è: merge e righello alla mano

Per superare questo ostacolo agilmente ho usato uno screen ruler. Io ho preferito "Free Ruler" per Mac OS X tra i vari righelli che ho trovato in rete, soprattutto per il suo tick mark interattivo che permette di fare una misura abbastanza accurata.

Ho aperto il pdf con il modulo da compilare, e poi ho misurato con il righello i punti in cui inserire i dati. Per creare il pdf con i dati di riempimento ho usato ReportLab che consente di scrivere stringhe di testo in un punto esatto, utilizzando le coordinate x e y.

Ecco la MIA ricetta

Passo 1

Aprire il pdf che rappresenta la base del nostro impasto, ovvero  il modulo da compilare, usando la classe PdfFileReader di pyPdf.

import codecs
from pyPdf import PdfFileWriter, PdfFileReader

input1 = PdfFileReader(codecs.open(path_modello_censimento, "rb"))

 

Passo 2

Preparare il pdf con i nostri canditi: i dati di riempimento. Qui entra in gioco ReportLab.

import StringIO
from reportlab.pdfgen import canvas
from reportlab.lib.units import cm

packet = StringIO.StringIO()
can = canvas.Canvas(packet)
...
textobject = can.beginText()
textobject.setTextOrigin( 11.94*cm, 20.12*cm)
textobject.textLine('hello world')
...
can.drawText(textobject)
can.showPage()
can.save()
packet.seek(0)

Come unità ho usato i centrimenti, sia nel fissare l'origine di ogni striga di testo inserita, sia quando ho misurato con il righello. 11.94 e 20.12 sono due esempi di coordinate.

Tenere presente che l'orgine si trova in basso a sinistra. Ma con l'istruzione seguente possiamo spostare l'orgine in alto.

can.translate(cm, cm)

 

Passo 3

Aprire il pdf creato sopra con PdfFileReader.

input2 = PdfFileReader(packet)

 

Passo 4

Aprire il pdf finale, che conterrà il merge dei due pdf precedenti con la classe PdfFileWriter di pyPdf.

output = PdfFileWriter()

 

Passo 5

Adesso la parte più divertente: "Impastare".

page0 = input1.getPage(0)
page0.mergePage(input2.getPage(0))
output.addPage(page0)

Dopo aver unito i due pdf pagina per pagina si arriva finalment al punto 6..

Passo 6

Adesso abbiamo il nostra risultato finale "output" che può essere memorizzato ovunque si voglia, io lo scrivo in un file temporaneo per completare l'esempio:

import tempfile
temp_file_name = tempfile.mktemp()
outputStream = codecs.open(temp_file_name, mode="wb")
output.write(outputStream)
outputStream.close()
os.unlink(temp_file_name)

 

L'elaborazione richiede un po' di tempo, ma il risultato finale è buono. Buon appetito!

Filed under: , ,
comments powered by Disqus