From b366d0972680fe5806066888546f963bd0d48239 Mon Sep 17 00:00:00 2001
From: Lucas Cimon <925560+Lucas-C@users.noreply.github.com>
Date: Sun, 13 Aug 2023 13:47:39 +0200
Subject: [PATCH] FPDF.image(), when provided a BytesIO instance, does not
close it anymore - fix #881
---
CHANGELOG.md | 2 ++
fpdf/image_parsing.py | 13 ++++++++-----
test/image/image_types/test_insert_images.py | 1 +
3 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 34028a387..a6b7ce3d1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,6 +19,8 @@ This can also be enabled programmatically with `warnings.simplefilter('default',
## [2.7.6] - Not released yet
### Added
* [`FPDF.write_html()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.write_html) now supports heading colors defined as attributes (_e.g._ `
...`)
+### Fixed
+* [`FPDF.image()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.image), when provided a `BytesIO` instance, does not close it anymore - _cf._ issue [#881](https://github.com/py-pdf/fpdf2/issues/881)
## [2.7.5] - 2023-08-04
### Added
diff --git a/fpdf/image_parsing.py b/fpdf/image_parsing.py
index b200cd42b..d79b4bb2f 100644
--- a/fpdf/image_parsing.py
+++ b/fpdf/image_parsing.py
@@ -14,7 +14,7 @@
RESAMPLE = Resampling.LANCZOS
except ImportError: # For Pillow < 9.1.0
- # pylint: disable=no-member
+ # pylint: disable=no-member, useless-suppression
RESAMPLE = Image.ANTIALIAS
except ImportError:
Image = None
@@ -116,6 +116,7 @@ def get_img_info(filename, img=None, image_filter="AUTO", dims=None):
raise EnvironmentError("Pillow not available - fpdf2 cannot insert images")
is_pil_img = True
+ keep_bytes_io_open = False
jpeg_inverted = False # flag to check whether a cmyk image is jpeg or not, if set to True the decode array is inverted in output.py
img_raw_data = None
if not img or isinstance(img, (Path, str)):
@@ -123,9 +124,8 @@ def get_img_info(filename, img=None, image_filter="AUTO", dims=None):
img = Image.open(img_raw_data)
is_pil_img = False
elif not isinstance(img, Image.Image):
- if isinstance(img, bytes):
- img = BytesIO(img)
- img_raw_data = img
+ keep_bytes_io_open = isinstance(img, BytesIO)
+ img_raw_data = BytesIO(img) if isinstance(img, bytes) else img
img = Image.open(img_raw_data)
is_pil_img = False
@@ -293,7 +293,10 @@ def get_img_info(filename, img=None, image_filter="AUTO", dims=None):
dp = f"/BlackIs1 true /Columns {w} /K -1 /Rows {h}"
if not is_pil_img:
- img.close()
+ if keep_bytes_io_open:
+ img.fp = None # cf. issue #881
+ else:
+ img.close()
info.update(
{
diff --git a/test/image/image_types/test_insert_images.py b/test/image/image_types/test_insert_images.py
index 983ce235e..be4b1ed6c 100644
--- a/test/image/image_types/test_insert_images.py
+++ b/test/image/image_types/test_insert_images.py
@@ -211,6 +211,7 @@ def test_insert_bytesio(tmp_path):
img.save(img_bytes, "PNG")
pdf.image(img_bytes, x=15, y=15, h=140)
assert_pdf_equal(pdf, HERE / "image_types_insert_png.pdf", tmp_path)
+ assert not img_bytes.closed # cf. issue #881
def test_insert_bytes(tmp_path):