Skip to content

Commit e04bd29

Browse files
write_html: fit a table wider than the page to the page width, and ignore a negative width (#2017)
1 parent 6bc2209 commit e04bd29

3 files changed

Lines changed: 33 additions & 0 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ This can also be enabled programmatically with `warnings.simplefilter('default',
4141
* `FPDF.write_html()` numbers an `<ol>` with an unknown `type`, such as `type="disc"`, as 1, 2, 3, like browsers, instead of raising `NotImplementedError` - thanks to @RavSinghChandan
4242
* `FPDF.write_html()` no longer raises `KeyError: 'href'` on an `<a>` element without an `href` attribute, such as a named anchor (`<a name="intro">`); its text is rendered as plain text - thanks to @RavSinghChandan
4343
* `FPDF.write_html()` treats an invalid `colspan` or `rowspan` on `<td>` / `<th>`, or one below 1, as 1 like browsers do, instead of raising `ValueError` or `ZeroDivisionError` - thanks to @RavSinghChandan
44+
* `FPDF.write_html()` renders a `<table>` whose `width` is wider than the page, such as `width="150%"`, at the page width with a warning, and ignores a negative `width` like browsers, instead of raising `ValueError` - thanks to @RavSinghChandan
4445
* warning detection during `FPDFRecorder.replay()` now correctly identifies context managers (`contextlib.AbstractContextManager`, `@contextmanager`, custom context managers) within `unbreakable()` sections
4546
* SVG import: `opacity`, `fill-opacity` and `stroke-opacity` accept percentages (`50%`), and an out-of-range `opacity` is clamped to 0-1 like the other two instead of raising `ValueError` - thanks to @RavSinghChandan
4647
* css `rgb()` colors accept percentages, as in `rgb(100%, 0%, 50%)` (clamped to 0%-100%), in SVG import and `FPDF.write_html()` instead of raising `ValueError` - thanks to @RavSinghChandan

‎fpdf/html.py‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1159,6 +1159,14 @@ def handle_starttag(self, tag: str, attrs: list[tuple[str, str | None]]) -> None
11591159
width = self.pdf.epw * float(width_str[:-1]) / 100
11601160
else:
11611161
width = _parse_html_dimension(width_str) / self.pdf.k
1162+
if width <= 0: # like browsers, an invalid width is ignored
1163+
width = None
1164+
elif width > self.pdf.epw:
1165+
LOGGER.warning(
1166+
'Table width="%s" is wider than the page: using the page width',
1167+
width_str,
1168+
)
1169+
width = self.pdf.epw
11621170
if "border" not in attrs_dict: # default borders
11631171
borders_layout = (
11641172
"HORIZONTAL_LINES"

‎test/html/test_html_table.py‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,3 +554,27 @@ def test_html_table_invalid_span_counts_as_one(tmp_path, span, value, text):
554554
render_span_table(span, f' {span}="1"', text),
555555
tmp_path,
556556
)
557+
558+
559+
@pytest.mark.parametrize("width", ["150%", "1000px", ' style="width: 120%"'])
560+
def test_html_table_wider_than_the_page_uses_the_page_width(tmp_path, caplog, width):
561+
attribute = width if width.startswith(" ") else f' width="{width}"'
562+
pdf = FPDF()
563+
pdf.add_page()
564+
pdf.write_html(f"<table{attribute}><tr><td>a</td><td>b</td></tr></table>")
565+
assert "wider than the page" in caplog.text
566+
expected = FPDF()
567+
expected.add_page()
568+
expected.write_html('<table width="100%"><tr><td>a</td><td>b</td></tr></table>')
569+
assert_pdf_equal(pdf, expected, tmp_path)
570+
571+
572+
@pytest.mark.parametrize("width", ["-50%", "-10"])
573+
def test_html_table_with_a_negative_width_ignores_it(tmp_path, width):
574+
pdf = FPDF()
575+
pdf.add_page()
576+
pdf.write_html(f'<table width="{width}"><tr><td>a</td><td>b</td></tr></table>')
577+
expected = FPDF()
578+
expected.add_page()
579+
expected.write_html("<table><tr><td>a</td><td>b</td></tr></table>")
580+
assert_pdf_equal(pdf, expected, tmp_path)

0 commit comments

Comments
 (0)