diff --git a/PIL/Image.py b/PIL/Image.py index cabc10743..bc8f91a54 100644 --- a/PIL/Image.py +++ b/PIL/Image.py @@ -548,10 +548,6 @@ class Image(object): had their file read and closed by the :py:meth:`~PIL.Image.Image.load` method. """ - try: - self.fp.close() - except Exception as msg: - logger.debug("Error closing: %s", msg) # Instead of simply setting to None, we're setting up a # deferred error that will better explain that the core image diff --git a/PIL/ImageFile.py b/PIL/ImageFile.py index 94f705b3c..4146520cf 100644 --- a/PIL/ImageFile.py +++ b/PIL/ImageFile.py @@ -117,6 +117,16 @@ class ImageFile(Image.Image): # directly after open, and closes file when finished. self.fp = None + def close(self): + if getattr(self, 'map', None): + self.map = None + try: + if self.fp: + self.fp.close() + except Exception as msg: + logger.debug("Error closing: %s", msg) + Image.Image.close(self) + def load(self): "Load image data based on tile list" diff --git a/PIL/TiffImagePlugin.py b/PIL/TiffImagePlugin.py index f1860e4aa..5d74296cc 100644 --- a/PIL/TiffImagePlugin.py +++ b/PIL/TiffImagePlugin.py @@ -944,6 +944,11 @@ class TiffImageFile(ImageFile.ImageFile): self.seek(current) return self._is_animated + def close(self): + if self.__fp: + self.__fp = None + ImageFile.ImageFile.close(self) + def seek(self, frame): "Select a given frame as current image" self._seek(max(frame, 0)) # Questionable backwards compatibility. diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index 9913860ad..481eaa213 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -2,6 +2,7 @@ from __future__ import print_function import logging from io import BytesIO import struct +import sys from helper import unittest, PillowTestCase, hopper, py3 @@ -499,5 +500,23 @@ class TestFileTiff(PillowTestCase): with Image.open(mp) as im: self.assertEqual(im.n_frames, 3) + +@unittest.skipUnless(sys.platform.startswith('win32'), "Windows only") +class TestFileTiffW32(PillowTestCase): + def test_fd_leak(self): + tmpfile = self.tempfile("temp.tif") + import os + + with Image.open("Tests/images/uint16_1_4660.tif") as im: + im.save(tmpfile) + + im = Image.open(tmpfile) + im.load() + self.assertRaises(Exception, lambda: os.remove(tmpfile)) + + im.close() + os.remove(tmpfile) + + if __name__ == '__main__': unittest.main()