diff --git a/CHANGELOG.md b/CHANGELOG.md index de0f49290..5f8717543 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,19 +19,21 @@ This can also be enabled programmatically with `warnings.simplefilter('default', ## [2.7.10] - Not released yet ### Added * [`Templates`](https://py-pdf.github.io/fpdf2/fpdf/Templates.html) can now be also defined in JSON files. -* support to optionally set `wrapmode` in templates (default `"WORD"` can optionally be set to `"CHAR"` to support wrapping on characters for scripts like Chinese or Japanese) - _cf._ [#1159](https://github.com/py-pdf/fpdf2/issues/1159) -* support for quadratic and cubic Bézier curves with [`FPDF.bezier()`](https://py-pdf.github.io/fpdf2/fpdf/Shapes.html#fpdf.fpdf.FPDF.bezier) -* feature to identify the Unicode script of the input text and break it into fragments when different scripts are used, improving text shaping results +* support to optionally set `wrapmode` in templates (default `"WORD"` can optionally be set to `"CHAR"` to support wrapping on characters for scripts like Chinese or Japanese) - _cf._ [#1159](https://github.com/py-pdf/fpdf2/issues/1159) - thanks to @carlhiggs +* support for quadratic and cubic Bézier curves with [`FPDF.bezier()`](https://py-pdf.github.io/fpdf2/fpdf/Shapes.html#fpdf.fpdf.FPDF.bezier) - thanks to @awmc000 +* feature to identify the Unicode script of the input text and break it into fragments when different scripts are used, improving [text shaping](https://py-pdf.github.io/fpdf2/TextShaping.html) results * [`FPDF.image()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.image): now handles `keep_aspect_ratio` in combination with an enum value provided to `x` * file names are mentioned in errors when `fpdf2` fails to parse a SVG image -* [`FPDF.write_html()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.write_html): spacing before lists can now be adjusted via the `HTML2FPDF.list_vertical_margin` attribute +* [`FPDF.write_html()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.write_html): now supports CSS page breaks properties : [documentation](https://py-pdf.github.io/fpdf2/HTML.html#page-breaks) +* [`FPDF.write_html()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.write_html): spacing before lists can now be adjusted via the `HTML2FPDF.list_vertical_margin` attribute - thanks to @lcgeneralprojects ### Fixed * [`FPDF.local_context()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.local_context) used to leak styling during page breaks, when rendering `footer()` & `header()` * [`fpdf.drawing.DeviceCMYK`](https://py-pdf.github.io/fpdf2/fpdf/drawing.html#fpdf.drawing.DeviceCMYK) objects can now be passed to [`FPDF.set_draw_color()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.set_draw_color), [`FPDF.set_fill_color()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.set_fill_color) and [`FPDF.set_text_color()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.set_text_color) without raising a `ValueError`: [documentation](https://py-pdf.github.io/fpdf2/Text.html#text-formatting). * [`FPDF.write_html()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.write_html): fixing rendering of `
Hello world. I am tired.
right aligned text
-i am a paragraph
in two parts.
i am a paragraph
in two parts.
hello in green
hello small
hello helvetica
@@ -79,7 +79,7 @@ pdf.output("html.pdf") ``` -## Styling HTML tags globally +### Styling HTML tags globally _New in [:octicons-tag-24: 2.7.9](https://github.com/py-pdf/fpdf2/blob/master/CHANGELOG.md)_ @@ -124,6 +124,7 @@ pdf.output("html_dd_indented.pdf") * ``: paragraphs (and `align`, `line-height` attributes)
+* `
` & `
+Top of a new page. +
+``` ## Known limitations diff --git a/docs/Shapes.md b/docs/Shapes.md index 72cc00b51..8437d2256 100644 --- a/docs/Shapes.md +++ b/docs/Shapes.md @@ -162,6 +162,8 @@ pdf.output("solid_arc.pdf") ![](solid_arc.png) ## Bezier Curve ## +_New in [:octicons-tag-24: 2.7.10](https://github.com/py-pdf/fpdf2/blob/master/CHANGELOG.md)_ + Using [`bezier()`](fpdf/fpdf.html#fpdf.fpdf.FPDF.bezier) to create a cubic Bezier curve: ```python from fpdf import FPDF diff --git a/docs/Tables.md b/docs/Tables.md index 9b8a1847d..464e42eae 100644 --- a/docs/Tables.md +++ b/docs/Tables.md @@ -224,6 +224,8 @@ The cell color is set following those settings, ordered by priority: 4. The table setting `cell_fill_color`, if `cell_fill_mode` indicates to fill a cell 5. The document `.fill_color` set before rendering the table +_New in [:octicons-tag-24: 2.7.9](https://github.com/py-pdf/fpdf2/blob/master/CHANGELOG.md)_ + Finally, it is possible to define your own cell-filling logic: ```python diff --git a/docs/Templates.md b/docs/Templates.md index 7c902a381..e9f53d907 100644 --- a/docs/Templates.md +++ b/docs/Templates.md @@ -265,6 +265,7 @@ f.render("./template.pdf") See template.py or [Web2Py] (Web2Py.md) for a complete example. # Example - Elements defined in JSON file # +_New in [:octicons-tag-24: 2.7.10](https://github.com/py-pdf/fpdf2/blob/master/CHANGELOG.md)_ The JSON file must consist of an array of objects. Each object with its name/value pairs define a template element: diff --git a/docs/Text.md b/docs/Text.md index 9237038d5..565c09786 100644 --- a/docs/Text.md +++ b/docs/Text.md @@ -49,7 +49,8 @@ For all text insertion methods, the relevant font related properties (eg. font/s All three `set_*_colors()` methods accept either a single greyscale value, 3 values as RGB components, a single `#abc` or `#abcdef` hexadecimal color string, or an instance of [`fpdf.drawing.DeviceCMYK`](https://py-pdf.github.io/fpdf2/fpdf/drawing.html#fpdf.drawing.DeviceCMYK), [`fpdf.drawing.DeviceRGB`](https://py-pdf.github.io/fpdf2/fpdf/drawing.html#fpdf.drawing.DeviceRGB) or [`fpdf.drawing.DeviceGray`](https://py-pdf.github.io/fpdf2/fpdf/drawing.html#fpdf.drawing.DeviceGray). You can even use [named web colors](https://en.wikipedia.org/wiki/Web_colors#HTML_color_names) by using [`html.color_as_decimal()`](fpdf/html.html#fpdf.html.color_as_decimal). -In addition, some of the methods can optionally use [markdown](TextStyling.md#markdowntrue) or [HTML](HTML.md) markup in the supplied text in order to change the font style (bold/italic/underline) of parts of the output. +More text styling options can be found on the page [Text styling](TextStyling.md), +including [Markdown syntax](TextStyling.md#markdowntrue) and [HTML markup](HTML.md). ## Change in current position `.cell()` and `.multi_cell()` let you specify where the current position (`.x`/`.y`) should go after the call. diff --git a/docs/TextStyling.md b/docs/TextStyling.md index cdcd2c97b..899ef6044 100644 --- a/docs/TextStyling.md +++ b/docs/TextStyling.md @@ -1,8 +1,8 @@ # Text styling # -## set_font() ## +## .set_font() ## -Setting emphasis on text can be controlled by using `set_font(style=...)`: +Setting emphasis on text can be controlled by using `.set_font(style=...)`: * `style="B"` indicates **bold** * `style="I"` indicates _italics_ @@ -66,6 +66,10 @@ pdf.multi_cell(w=150, text=LOREM_IPSUM[:200], new_x="LEFT", fill=True) ``` ![](char_spacing.png) +For a more complete support of **Markdown** syntax, +check out this guide to combine `fpdf2` with the `mistletoe` library: +[Combine with mistletoe to use Markdown](CombineWithMistletoeoToUseMarkdown.md). + ## Subscript, Superscript, and Fractional Numbers @@ -175,7 +179,7 @@ More examples from [`test_text_mode.py`](https://github.com/py-pdf/fpdf2/blob/ma An optional `markdown=True` parameter can be passed to the [`cell()`](fpdf/fpdf.html#fpdf.fpdf.FPDF.cell) & [`multi_cell()`](fpdf/fpdf.html#fpdf.fpdf.FPDF.multi_cell) methods -in order to enable basic Markdown-like styling: `**bold**, __italics__, --underlined--` +in order to enable basic Markdown-like styling: `**bold**, __italics__, --underlined--`. Bold & italics require using dedicated fonts for each style. @@ -199,9 +203,9 @@ Several unit tests in `test/text/` demonstrate that: * [test_multi_cell_markdown_with_ttf_fonts](https://github.com/py-pdf/fpdf2/blob/2.6.1/test/text/test_multi_cell_markdown.py#L27) -## write_html ## +## .write_html() ## -[`write_html`](HTML.md) allows to set emphasis on text through the ``, `` and `` tags: +[`.write_html()`](HTML.md) allows to set emphasis on text through the ``, `` and `` tags: ```python pdf.write_html("""bold diff --git a/docs/index.md b/docs/index.md index acfeb9ada..fd9db7618 100644 --- a/docs/index.md +++ b/docs/index.md @@ -41,7 +41,7 @@ Go try it **now** online in a Jupyter notebook: [![Open In Colab](https://colab. * It has very few dependencies: [Pillow](https://pillow.readthedocs.io/en/stable/), [defusedxml](https://pypi.org/project/defusedxml/), & [fonttools](https://pypi.org/project/fonttools/) * Can render [mathematical equations & charts](https://py-pdf.github.io/fpdf2/Maths.html) * Many example scripts available throughout this documentation, including usage examples with [Django](https://www.djangoproject.com/), [Flask](https://flask.palletsprojects.com), [FastAPI](https://fastapi.tiangolo.com/), [streamlit](https://streamlit.io/), AWS lambdas... : [Usage in web APIs](UsageInWebAPI.md) -* Unit tests with `qpdf`-based PDF diffing, and PDF samples validation using 3 different checkers: +* more than 1300 unit tests with `qpdf`-based PDF diffing, and PDF samples validation using 3 different checkers: [![QPDF logo](qpdf-logo.svg)](https://github.com/qpdf/qpdf) [![PDF Checker logo](pdfchecker-logo.png)](https://www.datalogics.com/products/pdf-tools/pdf-checker/) diff --git a/fpdf/fpdf.py b/fpdf/fpdf.py index 43baeafb6..e60f23404 100644 --- a/fpdf/fpdf.py +++ b/fpdf/fpdf.py @@ -2770,6 +2770,7 @@ def local_context(self, **kwargs): fill_opacity font_family font_size + font_size_pt font_style font_stretching intersection_rule @@ -2807,7 +2808,7 @@ def _start_local_context( self, font_family=None, font_style=None, - font_size=None, + font_size_pt=None, line_width=None, draw_color=None, fill_color=None, @@ -2819,11 +2820,16 @@ def _start_local_context( This method starts a "q/Q" context in the page content stream, and inserts operators in it to initialize all the PDF settings specified. """ - if "font_size_pt" in kwargs: - if font_size is not None: + if "font_size" in kwargs: + # At some point we may want to deprecate font_size here in favour of font_size_pt, + # and raise a warning if font_size is provided: + # * font_size_pt is more consistent with the size parameter of .set_font(), provided in points. + # * font_size can be misused, as users may not be aware of the difference between the 2 properties, + # and may erroneously provide a value in points as font_size. + if font_size_pt is not None: raise ValueError("font_size & font_size_pt cannot be both provided") - font_size = kwargs["font_size_pt"] / self.k - del kwargs["font_size_pt"] + font_size_pt = kwargs["font_size"] * self.k + del kwargs["font_size"] gs = None for key, value in kwargs.items(): if key in ( @@ -2868,11 +2874,15 @@ def _start_local_context( else: self._out("q") # All the following calls to .set*() methods invoke .out() and write to the stream buffer: - if font_family is not None or font_style is not None or font_size is not None: + if ( + font_family is not None + or font_style is not None + or font_size_pt is not None + ): self.set_font( font_family or self.font_family, font_style or self.font_style, - font_size or self.font_size_pt, + font_size_pt or self.font_size_pt, ) if line_width is not None: self.set_line_width(line_width) @@ -3586,15 +3596,19 @@ def _perform_page_break(self): # by popping out every GraphicsState: gs_stack = [] while self._is_current_graphics_state_nested(): + gs_stack.append(self._get_current_graphics_state()) + self._pop_local_stack() # This code assumes that every Graphics State in the stack # has been pushed in it while adding a "q" in the PDF stream # (which is what FPDF.local_context() does): self._end_local_context() - gs_stack.append(self._pop_local_stack()) + # Using a temporary GS to render header & footer: + self._push_local_stack() self.add_page(same=True) for prev_gs in reversed(gs_stack): - self._push_local_stack(prev_gs) self._start_local_context(**prev_gs) + self._push_local_stack() + self._pop_local_stack() self.x = x # restore x but not y after drawing header def _has_next_page(self): diff --git a/fpdf/html.py b/fpdf/html.py index 601a7c323..fa47bd098 100644 --- a/fpdf/html.py +++ b/fpdf/html.py @@ -12,7 +12,7 @@ from .deprecation import get_stack_level from .drawing import color_from_hex_string, convert_to_device_color -from .enums import TextEmphasis, XPos, YPos +from .enums import Align, TextEmphasis, XPos, YPos from .errors import FPDFException from .fonts import FontFace from .table import Table @@ -325,7 +325,7 @@ def __init__( self.emphasis = dict(b=False, i=False, u=False) self.font_size = pdf.font_size_pt self.set_font(pdf.font_family or "times", size=self.font_size, set_default=True) - + self._page_break_after_paragraph = False self._pre_formatted = False # preserve whitespace while True. # nothing written yet to, remove one initial nl: self._pre_started = False @@ -338,9 +338,8 @@ def __init__( self.line_height_stack = [] self.ol_type = [] # when inside atag, can be "a", "A", "i", "I" or "1" self.bullet = [] - self.default_conversion_factor = ( - get_scale_factor("mm") / self.pdf.k - ) # factor for converting default values from mm to document units + # factor for converting default values from mm to document units: + self.default_conversion_factor = get_scale_factor("mm") / self.pdf.k if list_vertical_margin is None: # Default value of 2 to be multiplied by the conversion factor # for list_vertical_margin is given in mm @@ -464,6 +463,10 @@ def _end_paragraph(self): self._column.render() self._paragraph = None self.follows_trailing_space = True + if self._page_break_after_paragraph: + # pylint: disable=protected-access + self.pdf._perform_page_break() + self._page_break_after_paragraph = False def _write_paragraph(self, text, link=None): if not self._paragraph: @@ -537,6 +540,8 @@ def handle_data(self, data): else: self._write_data(data) self.follows_trailing_space = data[-1] == " " + if self._page_break_after_paragraph: + self._end_paragraph() def _write_data(self, data): if self.href: @@ -558,6 +563,10 @@ def handle_starttag(self, tag, attrs): LOGGER.debug("STARTTAG %s %s", tag, attrs) parse_style(attrs) self._tags_stack.append(tag) + if attrs.get("break-before") == "page": + self._end_paragraph() + # pylint: disable=protected-access + self.pdf._perform_page_break() if tag == "dt": self._new_paragraph( line_height=( @@ -640,10 +649,21 @@ def handle_starttag(self, tag, attrs): size=tag_style.size_pt or self.font_size, ) if tag == "hr": + self._end_paragraph() + width = attrs.get("width") + if width: + if width[-1] == "%": + width = self.pdf.epw * int(width[:-1]) / 100 + else: + width = int(width) / self.pdf.k + else: + width = self.pdf.epw + # Centering: + x_start = self.pdf.l_margin + (self.pdf.epw - width) / 2 self.pdf.line( - x1=self.pdf.l_margin, + x1=x_start, y1=self.pdf.y, - x2=self.pdf.l_margin + self.pdf.epw, + x2=x_start + width, y2=self.pdf.y, ) self._write_paragraph("\n") @@ -863,23 +883,20 @@ def handle_starttag(self, tag, attrs): self.table_row.cell(img=attrs["src"], img_fill_width=True) self.td_th["inserted"] = True return - if self.pdf.y + height > self.pdf.page_break_trigger: - self.pdf.add_page(same=True) - x, y = self.pdf.get_x(), self.pdf.get_y() + x = self.pdf.get_x() if self.align and self.align[0].upper() == "C": - x = self.pdf.w / 2 - width / 2 + x = Align.C LOGGER.debug( 'image "%s" x=%d y=%d width=%d height=%d', attrs["src"], x, - y, + self.pdf.get_y(), width, height, ) - info = self.pdf.image( - self.image_map(attrs["src"]), x, y, width, height, link=self.href + self.pdf.image( + self.image_map(attrs["src"]), x=x, w=width, h=height, link=self.href ) - self.pdf.set_y(y + info.rendered_height) if tag == "center": self._new_paragraph(align="C") if tag == "toc": @@ -891,6 +908,13 @@ def handle_starttag(self, tag, attrs): self.pdf.char_vpos = "SUP" if tag == "sub": self.pdf.char_vpos = "SUB" + if attrs.get("break-after") == "page": + if tag in ("br", "hr", "img"): + self._end_paragraph() + # pylint: disable=protected-access + self.pdf._perform_page_break() + else: + self._page_break_after_paragraph = True def handle_endtag(self, tag): LOGGER.debug("ENDTAG %s", tag) diff --git a/scripts/changed_pdfs_comparison.html b/scripts/changed_pdfs_comparison.html index e5b9ef57b..df1616c22 100644 --- a/scripts/changed_pdfs_comparison.html +++ b/scripts/changed_pdfs_comparison.html @@ -7,11 +7,15 @@ + LEFT: Version from
master
branch + - + RIGHT: Version from current branch +
{% for changed_pdf_file in changed_pdf_files %} {{ changed_pdf_file }}- +{% endfor %} diff --git a/scripts/compare-changed-pdfs.py b/scripts/compare-changed-pdfs.py index ebd48462b..48e08fc44 100755 --- a/scripts/compare-changed-pdfs.py +++ b/scripts/compare-changed-pdfs.py @@ -30,14 +30,14 @@ def scantree_dirs(path): yield from scantree_dirs(entry.path) -target_dir = sys.argv[1] if len(sys.argv) > 1 else "test" -print(f"Processing all PDF reference files in {target_dir}") +target_dir = sys.argv[1] if len(sys.argv) > 1 else "test/" +print(f"Processing all PDF reference files in directory {target_dir}") stdout = check_output("git diff --name-status master", shell=True) changed_pdf_files = [ line[1:].strip() for line in stdout.decode("utf-8").splitlines() - if line.startswith(f"M\t{target_dir}") + if line.startswith(f"M\t{target_dir}") and line.endswith(".pdf") ] TMP_DIR.mkdir(exist_ok=True) diff --git a/scripts/pdfchecker.py b/scripts/pdfchecker.py index c86d665a2..15ccbc0e1 100755 --- a/scripts/pdfchecker.py +++ b/scripts/pdfchecker.py @@ -7,6 +7,9 @@ # * parallelize the execution of this analysis on all PDF files # * allow to ignore some errors considered harmless, listed in pdfchecker-ignore.json +# Note: among the 3 checkers we use for fpdf2, PDF Checker is the only one that report errors +# for unbalanced q/Q contexts in content streams, even if it does not provide a clear message. + # USAGE: ./pdfchecker.py [$pdf_filepath|--process-all-test-pdf-files|--print-aggregated-report] import sys diff --git a/test/html/html_features.pdf b/test/html/html_features.pdf index c19c4e2a1..f2ea38245 100644 Binary files a/test/html/html_features.pdf and b/test/html/html_features.pdf differ diff --git a/test/html/html_img_without_height_at_page_bottom_triggers_page_break.pdf b/test/html/html_img_without_height_at_page_bottom_triggers_page_break.pdf new file mode 100644 index 000000000..a174a39e1 Binary files /dev/null and b/test/html/html_img_without_height_at_page_bottom_triggers_page_break.pdf differ diff --git a/test/html/html_page_break_after.pdf b/test/html/html_page_break_after.pdf new file mode 100644 index 000000000..5799ea35d Binary files /dev/null and b/test/html/html_page_break_after.pdf differ diff --git a/test/html/html_page_break_before.pdf b/test/html/html_page_break_before.pdf new file mode 100644 index 000000000..be48a0adf Binary files /dev/null and b/test/html/html_page_break_before.pdf differ diff --git a/test/html/html_table_with_multiline_cells_and_split_over_page.pdf b/test/html/html_table_with_multiline_cells_and_split_over_page.pdf index 317979244..f78c8b332 100644 Binary files a/test/html/html_table_with_multiline_cells_and_split_over_page.pdf and b/test/html/html_table_with_multiline_cells_and_split_over_page.pdf differ diff --git a/test/html/test_html.py b/test/html/test_html.py index cdbc13af1..752052554 100644 --- a/test/html/test_html.py +++ b/test/html/test_html.py @@ -53,18 +53,18 @@ def test_html_features(tmp_path): pdf.write_html("h4
") pdf.write_html("h5
") pdf.write_html("h6
") - pdf.write_html("Rendering <hr>:
") + pdf.write_html("Rendering two <hr> tags:
") + pdf.write_html('
') pdf.write_html("
") # Now inserting
tags until a page jump is triggered: - for _ in range(25): + for _ in range(24): pdf.write_html("
") pdf.write_html("i am preformatted text.") pdf.write_html("hello blockquote") pdf.write_html("") pdf.write_html("
- li1
- another
- l item
") pdf.write_html("
- li1
- another
- l item
") - pdf.write_html('
- description title
- description details
') - pdf.write_html("") + pdf.write_html("
") pdf.write_html( "" " " @@ -91,7 +91,7 @@ def test_html_features(tmp_path): " " "
" ) - pdf.write_html('') + pdf.write_html("
") pdf.write_html( '' " " @@ -173,6 +173,10 @@ def getrow(i): pdf.add_page() img_path = HERE.parent / "image/png_images/c636287a4d7cb1a36362f7f236564cef.png" pdf.write_html(f"") + # With an (incorrect) trailing slash: + pdf.write_html(f"") + # With an (incorrect) end tag: + pdf.write_html(f"") assert_pdf_equal(pdf, HERE / "html_features.pdf", tmp_path) @@ -481,8 +485,7 @@ def test_html_img_not_overlapping(tmp_path): pdf.add_page() pdf.write_html( """ -
text
-""" +text
""" ) assert_pdf_equal( pdf, @@ -491,6 +494,19 @@ def test_html_img_not_overlapping(tmp_path): ) +def test_html_img_without_height_at_page_bottom_triggers_page_break(tmp_path): + pdf = FPDF() + pdf.add_page() + pdf.y = 200 + img_path = HERE.parent / "image/png_images/c636287a4d7cb1a36362f7f236564cef.png" + pdf.write_html(f'') + assert_pdf_equal( + pdf, + HERE / "html_img_without_height_at_page_bottom_triggers_page_break.pdf", + tmp_path, + ) + + def test_warn_on_tags_not_matching(caplog): pdf = FPDF() pdf.add_page() @@ -826,3 +842,32 @@ def test_html_list_vertical_margin(tmp_path): """ pdf.write_html(html, list_vertical_margin=margin_value) assert_pdf_equal(pdf, HERE / "html_list_vertical_margin.pdf", tmp_path) + + +def test_html_page_break_before(tmp_path): + pdf = FPDF() + pdf.add_page() + pdf.write_html( + """Content on first page. +
+ Content on second page, with some slight top margin. ++ Content on third page. +
""" + ) + assert_pdf_equal(pdf, HERE / "html_page_break_before.pdf", tmp_path) + + +def test_html_page_break_after(tmp_path): + pdf = FPDF() + pdf.add_page() + pdf.write_html( + """Content on first page. +
+ Content on second page. ++ Other content on second page. +
+ Content on third page.""" + ) + assert_pdf_equal(pdf, HERE / "html_page_break_after.pdf", tmp_path) diff --git a/test/text/header_footer_and_local_context_font_size.pdf b/test/local_context_font_size_and_header_footer.pdf similarity index 81% rename from test/text/header_footer_and_local_context_font_size.pdf rename to test/local_context_font_size_and_header_footer.pdf index b4651ce63..1ba512fac 100644 Binary files a/test/text/header_footer_and_local_context_font_size.pdf and b/test/local_context_font_size_and_header_footer.pdf differ diff --git a/test/outline/html_toc.pdf b/test/outline/html_toc.pdf index 97310b583..f06a6167e 100644 Binary files a/test/outline/html_toc.pdf and b/test/outline/html_toc.pdf differ diff --git a/test/outline/html_toc_2_pages.pdf b/test/outline/html_toc_2_pages.pdf index 61d5e607d..30e02e659 100644 Binary files a/test/outline/html_toc_2_pages.pdf and b/test/outline/html_toc_2_pages.pdf differ diff --git a/test/outline/html_toc_with_custom_rendering.pdf b/test/outline/html_toc_with_custom_rendering.pdf index 1d6dcf7fe..ecbc5de94 100644 Binary files a/test/outline/html_toc_with_custom_rendering.pdf and b/test/outline/html_toc_with_custom_rendering.pdf differ diff --git a/test/outline/html_toc_with_h1_as_2nd_heading.pdf b/test/outline/html_toc_with_h1_as_2nd_heading.pdf index 732358e33..6ee0b65d4 100644 Binary files a/test/outline/html_toc_with_h1_as_2nd_heading.pdf and b/test/outline/html_toc_with_h1_as_2nd_heading.pdf differ diff --git a/test/test_graphics_context.py b/test/test_graphics_context.py index 0bf072af3..147e6c478 100644 --- a/test/test_graphics_context.py +++ b/test/test_graphics_context.py @@ -322,7 +322,7 @@ def test_local_context_init(tmp_path): pdf.add_page() pdf.set_font("Helvetica", "", 12) with pdf.local_context( - font_family="Courier", font_style="B", font_size=24, text_color=(255, 128, 0) + font_family="Courier", font_style="B", font_size_pt=24, text_color=(255, 128, 0) ): pdf.cell(text="Local context") pdf.ln() @@ -372,3 +372,24 @@ def test_invalid_local_context_init(): with pytest.raises(ValueError): with pdf.local_context(stroke_width=2): pass + + +def test_local_context_font_size_and_header_footer(tmp_path): # issue 1204 + class PDF(FPDF): + def header(self): + self.cell(text=f"Header {self.page_no()}") + self.ln() + + def footer(self): + self.set_y(-15) + self.cell(text=f"Footer {self.page_no()}") + + pdf = PDF() + pdf.set_font(family="helvetica", size=12) + pdf.add_page() + with pdf.local_context(font_size_pt=36): # LABEL C + pdf.multi_cell(w=0, text="\n".join(f"Line {i + 1}" for i in range(21))) + assert pdf.font_size_pt == 12 + assert_pdf_equal( + pdf, HERE / "local_context_font_size_and_header_footer.pdf", tmp_path + ) diff --git a/test/text/test_cell.py b/test/text/test_cell.py index d7401572d..d2b130016 100644 --- a/test/text/test_cell.py +++ b/test/text/test_cell.py @@ -325,27 +325,6 @@ def test_cell_deprecated_txt_arg(): pdf.cell(txt="Lorem ipsum Ut nostrud irure") -def test_header_footer_and_local_context_font_size(tmp_path): # issue 1204 - class PDF(FPDF): - def header(self): - self.cell(text=f"Header {self.page_no()}") - self.ln() - - def footer(self): - self.set_y(-15) - self.cell(text=f"Footer {self.page_no()}") - - pdf = PDF() - pdf.set_font(family="helvetica", size=12) - pdf.add_page() - with pdf.local_context(font_size=36): # LABEL C - pdf.multi_cell(w=0, text="\n".join(f"Line {i + 1}" for i in range(21))) - assert pdf.font_size_pt == 12 - assert_pdf_equal( - pdf, HERE / "header_footer_and_local_context_font_size.pdf", tmp_path - ) - - @ensure_exec_time_below(seconds=24) @ensure_rss_memory_below(mib=1) def test_cell_speed_with_long_text(): # issue #907