From 3272b85f864d28c7d793d5fb066bef3256d45ffa Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sun, 12 Jul 2015 15:01:14 -0500 Subject: [PATCH 01/12] Do not let PIL handle the file handle --- skimage/io/_plugins/pil_plugin.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/skimage/io/_plugins/pil_plugin.py b/skimage/io/_plugins/pil_plugin.py index f7c10789..379ffbd9 100644 --- a/skimage/io/_plugins/pil_plugin.py +++ b/skimage/io/_plugins/pil_plugin.py @@ -43,19 +43,20 @@ def imread(fname, dtype=None, img_num=None, **kwargs): if fname.lower().endswith(('.tiff', '.tif')): return tif_imread(fname, **kwargs) - im = Image.open(fname) - try: - # this will raise an IOError if the file is not readable - im.getdata()[0] - except IOError as e: - site = "http://pillow.readthedocs.org/en/latest/installation.html#external-libraries" - pillow_error_message = str(e) - error_message = ('Could not load "%s" \n' - 'Reason: "%s"\n' - 'Please see documentation at: %s') % (fname, pillow_error_message, site) - raise ValueError(error_message) - else: - return pil_to_ndarray(im, dtype=dtype, img_num=img_num) + with open(fname, 'rb') as f: + im = Image.open(f) + try: + # this will raise an IOError if the file is not readable + im.getdata()[0] + except IOError as e: + site = "http://pillow.readthedocs.org/en/latest/installation.html#external-libraries" + pillow_error_message = str(e) + error_message = ('Could not load "%s" \n' + 'Reason: "%s"\n' + 'Please see documentation at: %s') % (fname, pillow_error_message, site) + raise ValueError(error_message) + else: + return pil_to_ndarray(im, dtype=dtype, img_num=img_num) def pil_to_ndarray(im, dtype=None, img_num=None): From e1596aef1b7e4b99b5c88cb24b685c921f6f764e Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sun, 12 Jul 2015 15:11:27 -0500 Subject: [PATCH 02/12] Remove unclosed file guards --- skimage/_shared/testing.py | 12 ++++++------ skimage/io/tests/test_pil.py | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/skimage/_shared/testing.py b/skimage/_shared/testing.py index 301d25ec..779cbe5c 100644 --- a/skimage/_shared/testing.py +++ b/skimage/_shared/testing.py @@ -119,7 +119,7 @@ def color_check(plugin, fmt='png'): testing.assert_allclose(img2.astype(np.uint8), r2) img3 = img_as_float(img) - with expected_warnings(['precision loss|unclosed file']): + with expected_warnings(['precision loss']): r3 = roundtrip(img3, plugin, fmt) testing.assert_allclose(r3, img) @@ -131,12 +131,12 @@ def color_check(plugin, fmt='png'): r4 = roundtrip(img4, plugin, fmt) testing.assert_allclose(r4, img4) else: - with expected_warnings(['sign loss|precision loss|unclosed file']): + with expected_warnings(['sign loss|precision loss']): r4 = roundtrip(img4, plugin, fmt) testing.assert_allclose(r4, img_as_ubyte(img4)) img5 = img_as_uint(img) - with expected_warnings(['precision loss|unclosed file']): + with expected_warnings(['precision loss']): r5 = roundtrip(img5, plugin, fmt) testing.assert_allclose(r5, img) @@ -156,14 +156,14 @@ def mono_check(plugin, fmt='png'): testing.assert_allclose(img2.astype(np.uint8), r2) img3 = img_as_float(img) - with expected_warnings(['precision|unclosed file|\A\Z']): + with expected_warnings(['precision|\A\Z']): r3 = roundtrip(img3, plugin, fmt) if r3.dtype.kind == 'f': testing.assert_allclose(img3, r3) else: testing.assert_allclose(r3, img_as_uint(img)) - with expected_warnings(['precision loss|unclosed file']): + with expected_warnings(['precision loss']): img4 = img_as_int(img) if fmt.lower() in (('tif', 'tiff')): img4 -= 100 @@ -171,7 +171,7 @@ def mono_check(plugin, fmt='png'): r4 = roundtrip(img4, plugin, fmt) testing.assert_allclose(r4, img4) else: - with expected_warnings(['precision loss|sign loss|unclosed file']): + with expected_warnings(['precision loss|sign loss']): r4 = roundtrip(img4, plugin, fmt) testing.assert_allclose(r4, img_as_uint(img4)) diff --git a/skimage/io/tests/test_pil.py b/skimage/io/tests/test_pil.py index cc00e19e..935dc6a7 100644 --- a/skimage/io/tests/test_pil.py +++ b/skimage/io/tests/test_pil.py @@ -160,7 +160,7 @@ def test_imsave_filelike(): s = BytesIO() # save to file-like object - with expected_warnings(['precision loss|unclosed file', + with expected_warnings(['precision loss', 'is a low contrast image']): imsave(s, image) @@ -230,9 +230,9 @@ class TestSaveTIF: def roundtrip(self, dtype, x, compress): with temporary_file(suffix='.tif') as fname: if dtype == np.bool: - expected = ['low contrast|unclosed file'] + expected = ['low contrast'] else: - expected = ['unclosed file|\A\Z'] + expected = ['\A\Z'] with expected_warnings(expected): if compress > 0: imsave(fname, x, compress=compress) From 7720527c95c2d22b8b3aa1b552b6303aef262e6a Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sun, 12 Jul 2015 15:17:58 -0500 Subject: [PATCH 03/12] Fix imsave test --- skimage/io/tests/test_pil.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/skimage/io/tests/test_pil.py b/skimage/io/tests/test_pil.py index 935dc6a7..fc20edee 100644 --- a/skimage/io/tests/test_pil.py +++ b/skimage/io/tests/test_pil.py @@ -166,6 +166,8 @@ def test_imsave_filelike(): # read from file-like object s.seek(0) + im = Image.open(s) + out = pil_to_ndarray(im) out = imread(s) assert out.shape == shape assert_allclose(out, image) From f1471dfd72d04267e383776c17da9a9f55f223b9 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sun, 12 Jul 2015 15:42:53 -0500 Subject: [PATCH 04/12] Remove offending line --- skimage/io/tests/test_pil.py | 1 - 1 file changed, 1 deletion(-) diff --git a/skimage/io/tests/test_pil.py b/skimage/io/tests/test_pil.py index fc20edee..1a7b7ff1 100644 --- a/skimage/io/tests/test_pil.py +++ b/skimage/io/tests/test_pil.py @@ -168,7 +168,6 @@ def test_imsave_filelike(): s.seek(0) im = Image.open(s) out = pil_to_ndarray(im) - out = imread(s) assert out.shape == shape assert_allclose(out, image) From 1a27bea7da1018d2154d0ae8b487f1f9cd560095 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sun, 12 Jul 2015 15:49:18 -0500 Subject: [PATCH 05/12] Allow pil imread to accept file-like objects again --- skimage/io/_plugins/pil_plugin.py | 34 +++++++++++++++++-------------- skimage/io/tests/test_pil.py | 3 +-- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/skimage/io/_plugins/pil_plugin.py b/skimage/io/_plugins/pil_plugin.py index 379ffbd9..475eb99c 100644 --- a/skimage/io/_plugins/pil_plugin.py +++ b/skimage/io/_plugins/pil_plugin.py @@ -13,8 +13,8 @@ def imread(fname, dtype=None, img_num=None, **kwargs): Parameters ---------- - fname : str - File name. + fname : str or file + File name or file-like-object. dtype : numpy dtype object or string specifier Specifies data type of array elements. img_num : int, optional @@ -43,20 +43,13 @@ def imread(fname, dtype=None, img_num=None, **kwargs): if fname.lower().endswith(('.tiff', '.tif')): return tif_imread(fname, **kwargs) - with open(fname, 'rb') as f: - im = Image.open(f) - try: - # this will raise an IOError if the file is not readable - im.getdata()[0] - except IOError as e: - site = "http://pillow.readthedocs.org/en/latest/installation.html#external-libraries" - pillow_error_message = str(e) - error_message = ('Could not load "%s" \n' - 'Reason: "%s"\n' - 'Please see documentation at: %s') % (fname, pillow_error_message, site) - raise ValueError(error_message) - else: + if isinstance(fname, string_types): + with open(fname, 'rb') as f: + im = Image.open(f) return pil_to_ndarray(im, dtype=dtype, img_num=img_num) + else: + im = Image.open(f) + return pil_to_ndarray(im, dtype=dtype, img_num=img_num) def pil_to_ndarray(im, dtype=None, img_num=None): @@ -67,6 +60,17 @@ def pil_to_ndarray(im, dtype=None, img_num=None): Refer to ``imread``. """ + try: + # this will raise an IOError if the file is not readable + im.getdata()[0] + except IOError as e: + site = "http://pillow.readthedocs.org/en/latest/installation.html#external-libraries" + pillow_error_message = str(e) + error_message = ('Could not load "%s" \n' + 'Reason: "%s"\n' + 'Please see documentation at: %s' + % (im.filename, pillow_error_message, site)) + raise ValueError(error_message) frames = [] grayscale = None i = 0 diff --git a/skimage/io/tests/test_pil.py b/skimage/io/tests/test_pil.py index 1a7b7ff1..935dc6a7 100644 --- a/skimage/io/tests/test_pil.py +++ b/skimage/io/tests/test_pil.py @@ -166,8 +166,7 @@ def test_imsave_filelike(): # read from file-like object s.seek(0) - im = Image.open(s) - out = pil_to_ndarray(im) + out = imread(s) assert out.shape == shape assert_allclose(out, image) From 2fb59b92435b9f67c091871cba701323b784ade7 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sun, 12 Jul 2015 19:28:30 -0500 Subject: [PATCH 06/12] Fix variable name --- skimage/io/_plugins/pil_plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skimage/io/_plugins/pil_plugin.py b/skimage/io/_plugins/pil_plugin.py index 475eb99c..fcd185ab 100644 --- a/skimage/io/_plugins/pil_plugin.py +++ b/skimage/io/_plugins/pil_plugin.py @@ -48,7 +48,7 @@ def imread(fname, dtype=None, img_num=None, **kwargs): im = Image.open(f) return pil_to_ndarray(im, dtype=dtype, img_num=img_num) else: - im = Image.open(f) + im = Image.open(fname) return pil_to_ndarray(im, dtype=dtype, img_num=img_num) From 66805cabdf9c37918992918f2cb3639ed7d61f46 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sun, 12 Jul 2015 21:47:48 -0500 Subject: [PATCH 07/12] Try fixing the remaining unclosed error --- skimage/_shared/testing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skimage/_shared/testing.py b/skimage/_shared/testing.py index 779cbe5c..603cfaaa 100644 --- a/skimage/_shared/testing.py +++ b/skimage/_shared/testing.py @@ -93,8 +93,8 @@ def roundtrip(img, plugin, suffix): if not '.' in suffix: suffix = '.' + suffix temp_file = NamedTemporaryFile(suffix=suffix, delete=False) - temp_file.close() fname = temp_file.name + temp_file.close() io.imsave(fname, img, plugin=plugin) new = io.imread(fname, plugin=plugin) try: From 6d7e0554a41aee80740d62befd4946927d141372 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sun, 12 Jul 2015 22:37:44 -0500 Subject: [PATCH 08/12] Use context manager for tif imread as well --- skimage/io/_plugins/pil_plugin.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/skimage/io/_plugins/pil_plugin.py b/skimage/io/_plugins/pil_plugin.py index fcd185ab..8d3bd977 100644 --- a/skimage/io/_plugins/pil_plugin.py +++ b/skimage/io/_plugins/pil_plugin.py @@ -41,7 +41,8 @@ def imread(fname, dtype=None, img_num=None, **kwargs): if hasattr(fname, 'lower') and dtype is None: kwargs.setdefault('key', img_num) if fname.lower().endswith(('.tiff', '.tif')): - return tif_imread(fname, **kwargs) + with open(fname, 'rb') as f: + return tif_imread(f, **kwargs) if isinstance(fname, string_types): with open(fname, 'rb') as f: From 182a6f69046463a6b946108b5d0e78fdeb3ebd18 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Mon, 13 Jul 2015 08:00:57 -0500 Subject: [PATCH 09/12] Fix handling of tiffile handles --- skimage/io/_plugins/pil_plugin.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/skimage/io/_plugins/pil_plugin.py b/skimage/io/_plugins/pil_plugin.py index 8d3bd977..bdffc0fd 100644 --- a/skimage/io/_plugins/pil_plugin.py +++ b/skimage/io/_plugins/pil_plugin.py @@ -5,7 +5,7 @@ from six import string_types from PIL import Image from ...util import img_as_ubyte, img_as_uint -from ...external.tifffile import imread as tif_imread, imsave as tif_imsave +from ...external.tifffile import TiffFile, imsave as tif_imsave def imread(fname, dtype=None, img_num=None, **kwargs): @@ -42,7 +42,8 @@ def imread(fname, dtype=None, img_num=None, **kwargs): kwargs.setdefault('key', img_num) if fname.lower().endswith(('.tiff', '.tif')): with open(fname, 'rb') as f: - return tif_imread(f, **kwargs) + tif = TiffFile(f) + return tif.asarray(**kwargs) if isinstance(fname, string_types): with open(fname, 'rb') as f: From b67a4e3076b6481f0f24349cabde375562977977 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 14 Jul 2015 06:45:31 -0500 Subject: [PATCH 10/12] Move the tifffile wrapper to tiff plugin --- skimage/io/_plugins/pil_plugin.py | 6 ++---- skimage/io/_plugins/tifffile_plugin.py | 29 +++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/skimage/io/_plugins/pil_plugin.py b/skimage/io/_plugins/pil_plugin.py index bdffc0fd..b806bd72 100644 --- a/skimage/io/_plugins/pil_plugin.py +++ b/skimage/io/_plugins/pil_plugin.py @@ -5,7 +5,7 @@ from six import string_types from PIL import Image from ...util import img_as_ubyte, img_as_uint -from ...external.tifffile import TiffFile, imsave as tif_imsave +from .tifffile import imread as tif_imread, imsave as tif_imsave def imread(fname, dtype=None, img_num=None, **kwargs): @@ -41,9 +41,7 @@ def imread(fname, dtype=None, img_num=None, **kwargs): if hasattr(fname, 'lower') and dtype is None: kwargs.setdefault('key', img_num) if fname.lower().endswith(('.tiff', '.tif')): - with open(fname, 'rb') as f: - tif = TiffFile(f) - return tif.asarray(**kwargs) + return tif_imread(fname, **kwargs) if isinstance(fname, string_types): with open(fname, 'rb') as f: diff --git a/skimage/io/_plugins/tifffile_plugin.py b/skimage/io/_plugins/tifffile_plugin.py index a3a766f1..3ae90449 100644 --- a/skimage/io/_plugins/tifffile_plugin.py +++ b/skimage/io/_plugins/tifffile_plugin.py @@ -1 +1,28 @@ -from ...external.tifffile import imread, imsave +from ...external.tifffile import TiffFile, imsave + + +def imread(fname, dtype=None, **kwargs): + """Load a tiff image from file. + + Parameters + ---------- + fname : str or file + File name or file-like-object. + dtype : numpy dtype object or string specifier + Specifies data type of array elements (Not currently used). + kwargs : keyword pairs, optional + Addition keyword arguments to pass through (see `tifffile`'s `imread` function). + + Notes + ----- + Provided by Christophe Golhke's tifffile.py [1]_, and supports many + advanced image types including multi-page and floating point. + + References + ---------- + .. [1] http://www.lfd.uci.edu/~gohlke/code/tifffile.py + + """ + with open(fname, 'rb') as f: + tif = TiffFile(f) + return tif.asarray(**kwargs) From f6653b781f0064298f174007c2c67e92bf48de61 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 14 Jul 2015 06:55:26 -0500 Subject: [PATCH 11/12] Fix tifffile plugin import --- skimage/io/_plugins/pil_plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skimage/io/_plugins/pil_plugin.py b/skimage/io/_plugins/pil_plugin.py index b806bd72..4e830438 100644 --- a/skimage/io/_plugins/pil_plugin.py +++ b/skimage/io/_plugins/pil_plugin.py @@ -5,7 +5,7 @@ from six import string_types from PIL import Image from ...util import img_as_ubyte, img_as_uint -from .tifffile import imread as tif_imread, imsave as tif_imsave +from .tifffile_plugin import imread as tif_imread, imsave as tif_imsave def imread(fname, dtype=None, img_num=None, **kwargs): From 8122e26731949415d6e9b6414e339903ecbec1bf Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 14 Jul 2015 09:28:53 -0500 Subject: [PATCH 12/12] Add another file guard --- skimage/io/collection.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/skimage/io/collection.py b/skimage/io/collection.py index bf8c58da..cf57f5f7 100644 --- a/skimage/io/collection.py +++ b/skimage/io/collection.py @@ -199,8 +199,9 @@ class ImageCollection(object): index = [] for fname in self._files: if fname.lower().endswith(('.tiff', '.tif')): - img = TiffFile(fname) - index += [(fname, i) for i in range(len(img.pages))] + with open(fname, 'rb') as f: + img = TiffFile(f) + index += [(fname, i) for i in range(len(img.pages))] else: try: im = Image.open(fname)