diff --git a/CHANGELOG.md b/CHANGELOG.md index 145330532..a758fc822 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ This can also be enabled programmatically with `warnings.simplefilter('default', * `FPDF.set_margins()`, `FPDF.set_left_margin()`, `FPDF.set_top_margin()` and `FPDF.set_right_margin()` raise a clear `ValueError` for a negative margin, like `FPDF.set_auto_page_break()` does for the bottom one, instead of writing text off the page - thanks to @RavSinghChandan * `FPDF.text_columns()` raises a clear `ValueError` for a negative `gutter`, like it does for `ncols` below 1, instead of silently laying out overlapping columns whose text is printed on top of each other - thanks to @RavSinghChandan * `FPDF.table()` raises a clear `ValueError` for a `width` or a single `col_widths` that is zero or negative, or a negative value in `col_widths`, instead of failing with an unrelated "Not enough horizontal space to render a single character" error - thanks to @RavSinghChandan +* `FPDF.set_font()`, `FPDF.set_font_size()` and `FPDF.set_stretching()` also raise their `ValueError` for NaN or infinity, instead of writing `nan Tz` or an infinite font size into the page, which is not a valid PDF number; `FPDF.write_html()` ignores an infinite ``, like a negative one - thanks to @RavSinghChandan * `FPDF.set_line_width()` and `FPDF.set_dash_pattern()` also raise their `ValueError` for NaN or infinity, instead of writing `nan w` or an infinite dash length into the page, which is not a valid PDF number - thanks to @RavSinghChandan * `FPDF.set_page_background()` raises a clear `ValueError` for a color tuple with a component outside [0, 255] or with neither 1 nor 3 values, like `FPDF.set_fill_color()` does, instead of failing only on the next `add_page()` (with a misleading `color component -1` message for 2 values, or a `TypeError` for 4) - thanks to @RavSinghChandan diff --git a/fpdf/fpdf.py b/fpdf/fpdf.py index d0cc2d90b..f260ddc18 100644 --- a/fpdf/fpdf.py +++ b/fpdf/fpdf.py @@ -2815,7 +2815,7 @@ def set_font( size (float): in points. The default value is the current size. Must be zero or a positive number. """ - if size < 0: + if not math.isfinite(size) or size < 0: raise ValueError(f"Font size must be zero or a positive number: {size}") if not family: family = self.font_family @@ -2898,7 +2898,7 @@ def set_font_size(self, size: float) -> None: Args: size (float): font size in points. Must be zero or a positive number. """ - if size < 0: + if not math.isfinite(size) or size < 0: raise ValueError(f"Font size must be zero or a positive number: {size}") if FloatTolerance.equal(self.font_size_pt, size): return @@ -2946,7 +2946,7 @@ def set_stretching(self, stretching: float) -> None: Args: stretching (float): horizontal stretching (scaling) in percents. Must be a positive number. """ - if stretching <= 0: + if not math.isfinite(stretching) or stretching <= 0: raise ValueError(f"Stretching must be a positive number: {stretching}") if self.font_stretching == stretching: return diff --git a/fpdf/html.py b/fpdf/html.py index f07b81cd7..eb6f1726e 100644 --- a/fpdf/html.py +++ b/fpdf/html.py @@ -11,6 +11,7 @@ # pyright: reportPrivateUsage=false import logging +import math import re import warnings from dataclasses import replace @@ -1230,8 +1231,8 @@ def handle_starttag(self, tag: str, attrs: list[tuple[str, str | None]]) -> None # like browsers, a CSS length such as "14pt" or "12px"; # a number without a unit is still read as points font_size = resolve_length(font_size_str) - # like browsers, a negative font size is ignored - if font_size >= 0: + # like browsers, a negative or infinite font size is ignored + if math.isfinite(font_size) and font_size >= 0: self.font_size_pt = font_size except ValueError: pass @@ -1239,7 +1240,7 @@ def handle_starttag(self, tag: str, attrs: list[tuple[str, str | None]]) -> None font_size_str = attrs_dict.get("size") or "" try: font_size = float(font_size_str) - if font_size >= 0: + if math.isfinite(font_size) and font_size >= 0: self.font_size_pt = font_size except ValueError: pass diff --git a/test/fonts/test_set_font.py b/test/fonts/test_set_font.py index 025cafd04..8aaca6bad 100644 --- a/test/fonts/test_set_font.py +++ b/test/fonts/test_set_font.py @@ -66,6 +66,18 @@ def test_set_font_negative_size(size): assert pdf.font_size_pt == 12 +@pytest.mark.parametrize("size", [float("nan"), float("inf")]) +def test_set_font_not_finite_size(size): + pdf = FPDF() + pdf.add_page() + pdf.set_font("Times", size=12) + with pytest.raises(ValueError, match="Font size must be zero or a positive number"): + pdf.set_font("Times", size=size) + with pytest.raises(ValueError, match="Font size must be zero or a positive number"): + pdf.set_font_size(size) + assert pdf.font_size_pt == 12 + + def test_set_builtin_font(tmp_path): pdf = FPDF() pdf.add_page() diff --git a/test/html/test_html.py b/test/html/test_html.py index 41ee3be20..3375f22a3 100644 --- a/test/html/test_html.py +++ b/test/html/test_html.py @@ -795,10 +795,11 @@ def test_html_font_css_font_size(tmp_path, html, equivalent): [ 'text', 'text', + 'text', ], ) def test_html_font_negative_size_is_ignored(tmp_path, html): - "Like browsers, a negative font size is ignored: the current size is kept." + "Like browsers, a negative or infinite font size is ignored: the current size is kept." pdf = FPDF() pdf.add_page() pdf.write_html(html) diff --git a/test/text/test_text.py b/test/text/test_text.py index ff85f8213..1a23fafa8 100644 --- a/test/text/test_text.py +++ b/test/text/test_text.py @@ -56,7 +56,7 @@ def test_text_stretch_spacing(tmp_path): assert_pdf_equal(doc, HERE / "text_stretch_spacing.pdf", tmp_path) -@pytest.mark.parametrize("stretching", [0, -50]) +@pytest.mark.parametrize("stretching", [0, -50, float("nan"), float("inf")]) def test_text_stretching_not_positive(stretching): doc = FPDF() doc.add_page()