From 64d84829b3038b6acf0142128f32f7d2bf23a46d Mon Sep 17 00:00:00 2001 From: CpDong <93034081+Bubbu0129@users.noreply.github.com> Date: Tue, 27 Dec 2022 09:02:43 +0800 Subject: [PATCH] Fix #632: without "height" attribute fails to leave enough blank space for itself (#634) Fixes https://github.com/PyFPDF/fpdf2/issues/632 --- CHANGELOG.md | 2 ++ fpdf/fpdf.py | 4 +++- fpdf/html.py | 4 +++- test/html/test_html.py | 15 +++++++++++++++ ...html_table_without_explicit_dimensions.pdf | Bin 14780 -> 14788 bytes test/html/test_img_not_overlapping.pdf | Bin 0 -> 11198 bytes test/image/test_load_image.py | 2 +- test/test_perfs.py | 2 +- 8 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 test/html/test_img_not_overlapping.pdf diff --git a/CHANGELOG.md b/CHANGELOG.md index 004ab4140..b2beddee2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ This can also be enabled programmatically with `warnings.simplefilter('default', ## [2.6.1] - not released yet ### Added +* ensured support for Python 3.11 * the `x` parameter of [`FPDF.image()`](https://pyfpdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.image) now accepts a value of `"C"` / `Align.C` / `"R"` / `Align.R` to horizontally position the image centered or aligned right * support for `[]()` links when `markdown=True` * support for `line-height` attribute of paragraph (`

`) in `write_html()` - thanks to @Bubbu0129 @@ -28,6 +29,7 @@ This can also be enabled programmatically with `warnings.simplefilter('default', ### Fixed * a `ValueError: Incoherent hierarchy` could be raised when using `write_html()` with some headings hierarchy * performance issue with adding large images with `FlateDecode` image filter +* image (``) without `height` attribute overlaps with the following content [#632](https://github.com/PyFPDF/fpdf2/issues/632) ## [2.6.0] - 2022-11-20 ### Added diff --git a/fpdf/fpdf.py b/fpdf/fpdf.py index b120d139f..4b6b5e769 100644 --- a/fpdf/fpdf.py +++ b/fpdf/fpdf.py @@ -3585,7 +3585,7 @@ def image( if link: self.link(x, y, w, h, link) - return info + return {**info, "rendered_width": w, "rendered_height": h} def _vector_image( self, @@ -3647,6 +3647,8 @@ def _vector_image( if link: self.link(x, y, w, h, link) + return {"rendered_width": w, "rendered_height": h} + def _downscale_image(self, name, img, info, w, h): width_in_pt, height_in_pt = w * self.k, h * self.k lowres_name = f"lowres-{name}" diff --git a/fpdf/html.py b/fpdf/html.py index 740362bad..acb774217 100644 --- a/fpdf/html.py +++ b/fpdf/html.py @@ -636,9 +636,11 @@ def handle_starttag(self, tag, attrs): width, height, ) - self.pdf.image( + image_info = self.pdf.image( self.image_map(attrs["src"]), x, y, width, height, link=self.href ) + width = image_info["rendered_width"] + height = image_info["rendered_height"] self.pdf.set_x(x + width) if self.table_col_index is not None: # in a : we grow the cell height according to the image height: diff --git a/test/html/test_html.py b/test/html/test_html.py index 878ca0902..a6e43a6b7 100644 --- a/test/html/test_html.py +++ b/test/html/test_html.py @@ -621,6 +621,21 @@ def test_html_custom_line_height(tmp_path): assert_pdf_equal(pdf, HERE / "html_custom_line_height.pdf", tmp_path) +def test_img_not_overlapping(tmp_path): + pdf = FPDF() + pdf.add_page() + pdf.write_html( + """ +

text

+""" + ) + assert_pdf_equal( + pdf, + HERE / "test_img_not_overlapping.pdf", + tmp_path, + ) + + def test_warn_on_tags_not_matching(caplog): pdf = FPDF() pdf.add_page() diff --git a/test/html/test_img_inside_html_table_without_explicit_dimensions.pdf b/test/html/test_img_inside_html_table_without_explicit_dimensions.pdf index 0500abe3537b2f38358894f4cf2cf2d2176d87b4..78983577fac863fc2217f3c63477ea3827f9a727 100644 GIT binary patch delta 397 zcmdl}e580oC1bsbF_)bkS8+*EYGN)|#hltcYc3{70oKo!N4ZTaZ{Pjw@5*|%WoKiO zLWe|UZFxXsz_q%_V3E`t)`@2-c7z_@5V|6e3>wvCIx0*02}KL0VH<9*Z9K+qmzc!OYF)O@5lzuaOl=Jh55!NlvqH24}G0VfApCFeZI@wwGjG!jRTh+w; z&i8L-{$}YYHUF|%lxdb(y@|1c0SGAMDR6-q1_ov(M(ARe<_0EcVul8$1{N4%W)|k? zVkSlg=;j%k7#l(CovdeR5$EV=?&R!jX=vbLU}0uyVr=YWVrF1$X6S5bW@2DuW@=|c dP(>^xfD?;KDvDCmxPTT|m~yGAy863u0RWC5csl?9 diff --git a/test/html/test_img_not_overlapping.pdf b/test/html/test_img_not_overlapping.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d65c643d9e21644832a8079afd6a4b5da22e000e GIT binary patch literal 11198 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