Solutie in Python pentru construire documente pdf cu imagini

Categorii: Programare

06-Apr-2018 17:24 - 125 vizionari

Exista in Python cateva solutii de construire a documentelor pdf, dar cel mai simplu (si care sa suporte si inserarea de imagini) este FPDF for Python.

Ieri am testat o solutie pentru un client si astazi m-am gandit ca ar fi bine sa o structurez sub forma unui utilitar de generare a documentelor pdf plecand de la o baza de date SQL si cateva sabloane.

Programul, in varianta ultra scurta, accepta ca argument un fisier-sablon si genereaza un document pdf conform sablonului.

Modulul fpdf se poate instala in Python cu comanda pip install fpdf

Daca programul se numeste main.py, el poate fi apelat:


#genereaza un test.pdf conform sablonului definit in interiorul programului
python main.py -t

#genereaza test1.pdf folosind test1.txt ca sablon
python main.py -i test1.txt -o test1.pdf


Programul main.py (varianta ultrascurta si compacta):



#
# Make PDF from template
#

import os, string, argparse
from fpdf import FPDF

def makePdf(template):
    width, height = 600, 800
    initFlag = False
    lin = 0
    fontsz = 12
    fontfm = 'Arial'
    fontst = 'B'
    for i in template.split('\n'):
        line = i.replace('\r','').lstrip()
        if not line:
            continue
        if line.startswith(';'):
            continue
        L = [x for x in line.split() if x]
        cmd = L[0].upper()
        rest = string.join(L[1:])
        if cmd == 'SZ':
            #set document size
            _w, _h = L[1].split(',')
            width, height = int(_w), int(_h)
        if not initFlag:
            initFlag = True
            pdf = FPDF(unit = "pt", format = [width, height])
            pdf.add_page()
            pdf.set_font('Arial', 'B', fontsz)
        if cmd == 'NEWP':
            #new page
            pdf.add_page()
        if cmd == 'FONTSZ':
            #font size
            fontsz = int(rest)
            pdf.set_font(fontfm, fontst, fontsz)
        if cmd == 'FONTFM':
            #font family
            fontfm = rest
            pdf.set_font(fontfm, fontst, fontsz)
        if cmd == 'FONTST':
            #font style
            fontst = rest
            pdf.set_font(fontfm, fontst, fontsz)
        if cmd == 'PR':
            #insert text with left align
            pdf.cell(0, fontsz, rest, align='L')
            pdf.ln()
            lin += fontsz
        if cmd == 'PRC':
            #insert centered text
            pdf.cell(0, fontsz, rest, align='C')
            pdf.ln()
            lin += fontsz
        if cmd == 'LN':
            pdf.ln()
            lin += fontsz
        if cmd == 'COL':
            #next 'pr' or 'prc' command will insert text starting from 'col' position
            col = int(L[1])
            pdf.cell(col)
        if cmd == 'IM':
            #insert image from local folder
            filename, _w, _h = L[1].split(',')
            width, height = int(_w), int(_h)
            filepath = os.path.sep.join((os.getcwd(), filename))
            pdf.image(filepath, w=width, h=height)
    output = pdf.output(None, "S")
    return output


template = '''
;
; Internal test template
;
sz 600,800
fontfm Arial
fontsz 32
pr Test 1 32 left
prc Test 2 32 center
pr Test 3 32 left
fontsz 16
pr Test 1 16 left
prc Test 2 16 center
pr Test 3 16 left
im 122.jpg,200,100
fontst 
fontfm Times
fontsz 32
pr Test font Times 32
prc Test font Times centered
im 200.jpg,200,100
fontsz 64
pr Test font Times 64
fontfm Arial
fontsz 32
pr Test font Arial 32
fontsz 24
pr Test font Arial 24
fontsz 16
pr Test font Arial 16
newp
fontfm Times
fontsz 32
pr Test On new page Times 32
fontfm Arial
fontsz 32
pr Test On new page Arial 32
'''

if __name__ == "__main__":
    try:
        parser = argparse.ArgumentParser()
        parser.add_argument("-t", help="demo generate test.pdf",
            action="store_true", default=False)
        parser.add_argument("-i", type=str, help="input filename")
        parser.add_argument("-o", type=str, help="output filename")
        args = parser.parse_args()
        if args.t:
            print 'Generate test.pdf from internal template'
            with open('test.pdf', 'wb') as f:
                f.write(makePdf(template))
        else:
            if args.i:
                inputfile = args.i
                outputfile = args.o or '{}.pdf'.format(inputfile)
                print 'Generate {} from {}'.format(outputfile, inputfile)
                with open(outputfile, 'wb') as f:
                    with open(inputfile, 'rb') as ff:
                        template = ff.read()
                    f.write(makePdf(template))
            else:
                parser.print_help()
    except Exception as ex:
        print ex

Sablonul de test inclus in program face referire la doua imagini jpg (122.jpg si 200.jpg) si imaginile trebuie sa existe in folderul curent.

Un alt exemplu de sablon:


;
; Sablon de test
;

sz 600,800
fontfm Arial
fontsz 32
prc Page 1
pr Test 1
fontsz 16
prc Page 1
pr Test 2
newp
fontsz 32
prc Page 2
pr Test 1
fontsz 16
prc Page 2
pr Test 2

Varianta pentru client include un server XML-RPC care stocheaza imagini si genereaza rapoarte pdf.



Ultimele pagini: RSS

Alte adrese de Internet

Categorii

Istoric



Contorizari incepand cu 9 iunie 2014:
Flag Counter

Atentie: Continutul acestui server reprezinta ideile mele si acestea pot fi gresite.