pythonpdf-generationfpdfpyfpdffpdf2

FPDF2 Template multiline space between text like a newline


If I'm using a FlexTemplate and feed multiline text into it. It displays the lines like it does a newline between each line break.

I tried the same text content with a normal multi_cell() and it is displayed just fine. But not in the template.

python version: 3.11.1

fpdf2 version: 2.7.9

Here is my code where you can directly see this behavior:

from datetime import datetime
from fpdf import FPDF
from fpdf import FlexTemplate

ra_address = "Dummy Firstname Lastname Streetname. 123 12345 London"
title = "Y o u   A r e   A m a z i n g"
logo_path = "assets/Logo-test.png"
generic_info = "Tel.: 000 / 000 000 0 - 0\nFax: 000 / 000 000 1\nMail: hello@example.uk"
created = "Created: "+datetime.now().strftime("%d.%m.%Y")
legend = """My Legend: CL = Countless:  1 = yearly / 2 = half / 4 = quarter / 5 = monthly / 6 = single  Options: C = Cookie / ED = Endcake / LW = Lower Water / ST = Storm / IZ = IceZip / GL = Global / UG = Unknown Geodez\u00ad
KIZ:   KH = KiloHertz  /  VK = ValonK  /  TK = TalonK  / SFR = SuperForeignRequest  /  SB = Sabertooth  /  Y = Yes   /  N = No  STA:   A = Active  /  Q = Quiet  /  S = Sold  /  F = Foreign  CC = CoveredCOOP  OP=OverPowered"""
pagecount = "1"


elements = [
    { 'name': 'my_logo', 'type': 'I', 'x1': 250, 'y1': 6, 'x2': 280, 'y2': 36, 'font': None, 'size': 0.0,  'align': 'C', 'priority': 2, },
    { 'name': 'my_info', 'type': 'T', 'x1': 228.6, 'y1': 36.7, 'x2': 281.1, 'y2': 45.7, 'font': 'calibri', 'size': 9.0, 'align': 'C', 'priority': 2, 'multiline': True, 'wrapmode': 'WORD'},
    { 'name': 'ra_address', 'type': 'T', 'x1': 11, 'y1': 19.10, 'x2': 78.92, 'y2': 31.1, 'font': 'calibri', 'size': 12,  'priority': 2, 'multiline': True, 'wrapmode': 'WORD'},
    { 'name': 'title_box', 'type': 'B', 'x1': 100, 'y1': 12.0, 'x2': 192, 'y2': 21, 'align': 'C', 'priority': 0, 'background': 0xaaffaa},
    { 'name': 'title', 'type': 'T', 'x1': 100, 'y1': 12.0, 'x2': 192, 'y2': 21, 'font': 'calibri', 'size': 16, 'bold': 1, 'align': 'C', 'priority': 2, 'foreground': 0x000000},
    { 'name': 'created', 'type': 'T', 'x1': 250, 'y1': 49.1, 'x2': 280, 'y2': 54.1, 'font': 'calibri', 'size': 10, 'bold': title, 'align': 'C', 'priority': 2},
    { 'name': 'legend', 'type': 'T', 'x1': 11, 'y1': 190, 'x2': 287, 'y2': 197, 'font': 'calibri', 'size': 7, 'bold': title, 'priority': 2, 'multiline': True, 'wrapmode': 'CHAR'},
    { 'name': 'pagecount', 'type': 'T', 'x1': 267, 'y1': 195.1, 'x2': 281, 'y2': 201.5, 'font': 'calibri', 'size': 8, 'align': 'C', 'priority': 3, },
]
pdf = FPDF(format="A4", orientation="landscape")
pdf.set_title("My awesome Title")
pdf.set_author("Ex Calibur")
pdf.set_margin(0)

pdf.add_font("calibri", style="", fname="assets/calibri.ttf")
pdf.add_font("calibri", style="b", fname="assets/calibrib.ttf")
pdf.add_font("calibri", style="i", fname="assets/calibrii.ttf")
pdf.add_font("calibri", style="bi", fname="assets/calibriz.ttf")
pdf.set_font("calibri")
pdf.set_text_color("#000000")
pdf.set_draw_color("#aaaaaa")
pdf.set_fill_color("#fefefe")

pdf.add_page()

pdf.set_xy(228.6, 36.7)
# the generic info when done directly with multi_cell does a correct line height
pdf.multi_cell(new_x="RIGHT", new_y="TOP", w=0, text=generic_info, align='C')



tmpl = FlexTemplate( pdf, elements=elements)
tmpl["ra_address"] = ra_address
tmpl["my_logo"] = logo_path
tmpl["my_info"] = generic_info
tmpl["title"] = title
tmpl["created"] = created
tmpl["legend"] = legend
tmpl["pagecount"] = pagecount

tmpl.render()

pdf.set_xy(10, 58)
TABLE_DATA = [
    { "config": { "colspan": 8 }, "values": ["Group 1"]},
    { "config": { }, "values":["Col 1", "Col 2", "Col 3", "Col 4", "Col 5", "Col 6", "Col 7", "Col 8"]},
    { "config": { }, "values":["Test data", "123-456-789", "abcdef", "01.01.2024", "01.01.2025", "1", "Code", "_.___"] },
    { "config": { "colspan": 8 }, "values":["Nested table with mostly one single row"] }
]

with pdf.table() as table:
    for data_row in TABLE_DATA:
        row_config = data_row.get("config")
        values = data_row.get("values")
        row = table.row()
        for val in values:
            row.cell(val, colspan=row_config.get("colspan", 0))

pdf.output("template-test.pdf")

The extra lines/spaces

How it should look like

Thank you


Solution

  • As explained here: https://github.com/py-pdf/fpdf2/issues/1237

    The y1 to y2 dimension of multiline text in a template expects the size of a single line, not of the whole block.

    Hint: A good value for y2 is: y2 = (font-size/2)+y1.