Skip to content

Template.split_multicell(): measure the element width in the template unit, not always in mm - #2140

Merged
andersonhc merged 2 commits into
py-pdf:masterfrom
Enesuygurs:fix/template-split-multicell-units
Nov 10, 2026
Merged

andersonhc merged 2 commits into
py-pdf:masterfrom
Enesuygurs:fix/template-split-multicell-units

Conversation

@Enesuygurs

Copy link
Copy Markdown

Template.split_multicell() (and FlexTemplate.split_multicell()) ignored the unit of the template document. It measures the text in a separate, private FPDF instance, so that the target document is not touched (issue #238), but that instance was created with FPDF(), i.e. always in millimeters. The element width x2 - x1 is given in the template's own unit, though, so as soon as a template was defined in anything other than mm, the text was split for the wrong width.

With an element that is 40 mm wide, defined in points:

from fpdf.template import Template

tmpl = Template(unit="pt", elements=[{
    "name": "t", "type": "T", "x1": 56.69, "y1": 10, "x2": 170.08, "y2": 20,
    "font": "helvetica", "size": 12,
}])
tmpl.split_multicell("Lorem ipsum dolor sit amet, consetetur sadipscing elitr, ...", "t")

Before: the width was read as 113.39 mm, so the lines came back almost three times wider than the element (the first one is about 293 pt wide for a 113 pt box). With unit="in" the same element is 1.57 "mm" wide and the call fails with FPDFException: Not enough horizontal space to render a single character.
After: the lines are the same as with the equivalent mm template, and each of them fits in the element.

The fix creates the splitting FPDF with the unit of the target document (FPDF(unit=self.pdf.k)), so the width is measured exactly as when the element is rendered.

The existing test_template_split_multicell test used unit="pt" with x1=20, x2=60, but its expected lines were only right because of this bug: they are the lines for a 40 mm wide element (a 40 pt wide box could not even hold "Lorem ipsum dolor" at 12 pt). I parametrized it over mm, cm, in and pt with the same 40 mm wide element, and it now checks that all four units give the same lines. Without the fix the cm, in and pt cases fail; with it all of them pass. The full test suite passes locally, and black, pylint and mypy are clean.

I did not find an existing issue for this, so there is no "Fixes #N".

Checklist:

  • A unit test is covering the code added / modified by this PR

  • In case of a new feature, docstrings have been added, with also some documentation in the docs/ folder N/A

  • A mention of the change is present in CHANGELOG.md

  • This PR is ready to be merged

By submitting this pull request, I confirm that my contribution is made under the terms of the GNU LGPL 3.0 license.

@andersonhc

Copy link
Copy Markdown
Collaborator

@allcontributors please add @Enesuygurs for code

@allcontributors

Copy link
Copy Markdown

@andersonhc

I've put up a pull request to add @Enesuygurs! 🎉

@andersonhc
andersonhc merged commit 32939f5 into py-pdf:master Nov 10, 2026
23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants