diff --git a/CHANGES.rst b/CHANGES.rst index a3527de7d..13afddc62 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,6 +5,12 @@ Changelog (Pillow) 8.4.0 (unreleased) ------------------ +- Catch TypeError from corrupted DPI value in EXIF #5639 + [homm, radarhere] + +- Do not close file pointer when saving SGI images #5645 + [farizrahman4u, radarhere] + - Deprecate ImagePalette size parameter #5641 [radarhere, hugovk] diff --git a/Tests/images/broken_exif_dpi.jpg b/Tests/images/broken_exif_dpi.jpg new file mode 100644 index 000000000..2c88b9463 Binary files /dev/null and b/Tests/images/broken_exif_dpi.jpg differ diff --git a/Tests/test_file_jpeg.py b/Tests/test_file_jpeg.py index 68096e92d..15518756c 100644 --- a/Tests/test_file_jpeg.py +++ b/Tests/test_file_jpeg.py @@ -718,6 +718,15 @@ class TestFileJpeg: # This should return the default, and not raise a ZeroDivisionError assert im.info.get("dpi") == (72, 72) + def test_dpi_exif_string(self): + # Arrange + # 0x011A tag in this exif contains string '300300\x02' + with Image.open("Tests/images/broken_exif_dpi.jpg") as im: + + # Act / Assert + # This should return the default + assert im.info.get("dpi") == (72, 72) + def test_no_dpi_in_exif(self): # Arrange # This is photoshop-200dpi.jpg with resolution removed from EXIF: diff --git a/Tests/test_file_sgi.py b/Tests/test_file_sgi.py index 0210dd4f1..6a5d8887d 100644 --- a/Tests/test_file_sgi.py +++ b/Tests/test_file_sgi.py @@ -73,6 +73,13 @@ def test_write(tmp_path): img.save(out, format="sgi") assert_image_equal_tofile(img, out) + out = str(tmp_path / "fp.sgi") + with open(out, "wb") as fp: + img.save(fp) + assert_image_equal_tofile(img, out) + + assert not fp.closed + for mode in ("L", "RGB", "RGBA"): roundtrip(hopper(mode)) diff --git a/docs/releasenotes/8.4.0.rst b/docs/releasenotes/8.4.0.rst new file mode 100644 index 000000000..42e57745b --- /dev/null +++ b/docs/releasenotes/8.4.0.rst @@ -0,0 +1,41 @@ +8.4.0 +----- + +API Changes +=========== + +Deprecations +^^^^^^^^^^^^ + +ImagePalette size parameter +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``size`` parameter will be removed in Pillow 10.0.0 (2023-01-02). + +Before Pillow 8.3.0, ``ImagePalette`` required palette data of particular lengths by +default, and the size parameter could be used to override that. Pillow 8.3.0 removed +the default required length, also removing the need for the size parameter. + +API Additions +============= + +TODO +^^^^ + +TODO + +Security +======== + +TODO +^^^^ + +TODO + +Other Changes +============= + +TODO +^^^^ + +TODO diff --git a/docs/releasenotes/index.rst b/docs/releasenotes/index.rst index e60d26ec7..55c51a401 100644 --- a/docs/releasenotes/index.rst +++ b/docs/releasenotes/index.rst @@ -14,6 +14,7 @@ expected to be backported to earlier versions. .. toctree:: :maxdepth: 2 + 8.4.0 8.3.1 8.3.0 8.2.0 diff --git a/src/PIL/JpegImagePlugin.py b/src/PIL/JpegImagePlugin.py index b18e8126f..b8674eeed 100644 --- a/src/PIL/JpegImagePlugin.py +++ b/src/PIL/JpegImagePlugin.py @@ -168,11 +168,11 @@ def APP(self, marker): # 1 dpcm = 2.54 dpi dpi *= 2.54 self.info["dpi"] = dpi, dpi - except (KeyError, SyntaxError, ValueError, ZeroDivisionError): + except (TypeError, KeyError, SyntaxError, ValueError, ZeroDivisionError): # SyntaxError for invalid/unreadable EXIF # KeyError for dpi not included # ZeroDivisionError for invalid dpi rational value - # ValueError for dpi being an invalid float + # ValueError or TypeError for dpi being an invalid float self.info["dpi"] = 72, 72 diff --git a/src/PIL/SgiImagePlugin.py b/src/PIL/SgiImagePlugin.py index d0f7c9993..5f1ef6edc 100644 --- a/src/PIL/SgiImagePlugin.py +++ b/src/PIL/SgiImagePlugin.py @@ -193,7 +193,8 @@ def _save(im, fp, filename): for channel in im.split(): fp.write(channel.tobytes("raw", rawmode, 0, orientation)) - fp.close() + if hasattr(fp, "flush"): + fp.flush() class SGI16Decoder(ImageFile.PyDecoder):