[med-svn] [Git][python-team/modules/tifffile][upstream] New upstream version 20200603
Ole Streicher
gitlab at salsa.debian.org
Fri Jun 12 11:09:03 BST 2020
Ole Streicher pushed to branch upstream at Debian Python Team / DPMT / tifffile
Commits:
c3951b75 by Ole Streicher at 2020-06-12T12:06:02+02:00
New upstream version 20200603
- - - - -
8 changed files:
- CHANGES.rst
- PKG-INFO
- README.rst
- setup.py
- tests/test_tifffile.py
- tifffile.egg-info/PKG-INFO
- tifffile.egg-info/requires.txt
- tifffile/tifffile.py
Changes:
=====================================
CHANGES.rst
=====================================
@@ -1,7 +1,17 @@
Revisions
---------
-2020.5.11
+2020.6.3
Pass 2908 tests.
+ Support os.PathLike file names (#9).
+2020.5.30
+ Re-add pure Python PackBits decoder.
+2020.5.25
+ Make imagecodecs an optional dependency again.
+ Disable multi-threaded decoding of small LZW compressed segments.
+ Fix caching of TiffPage.decode function.
+ Fix xml.etree.cElementTree ImportError on Python 3.9.
+ Fix tostring DeprecationWarning.
+2020.5.11
Fix reading ImageJ grayscale mode RGB images (#6).
Remove napari reader plugin.
2020.5.7
=====================================
PKG-INFO
=====================================
@@ -1,11 +1,13 @@
Metadata-Version: 2.1
Name: tifffile
-Version: 2020.5.11
+Version: 2020.6.3
Summary: Read and write TIFF(r) files
Home-page: https://www.lfd.uci.edu/~gohlke/
Author: Christoph Gohlke
Author-email: cgohlke at uci.edu
License: BSD
+Project-URL: Bug Tracker, https://github.com/cgohlke/tifffile/issues
+Project-URL: Source Code, https://github.com/cgohlke/tifffile
Description: Read and write TIFF(r) files
============================
@@ -46,23 +48,33 @@ Description: Read and write TIFF(r) files
:License: BSD 3-Clause
- :Version: 2020.5.11
+ :Version: 2020.6.3
Requirements
------------
This release has been tested with the following requirements and dependencies
(other versions may work):
- * `CPython 3.6.8, 3.7.7, 3.8.2 64-bit <https://www.python.org>`_
- * `Numpy 1.16.6 <https://www.numpy.org>`_
- * `Imagecodecs 2020.2.18 <https://pypi.org/project/imagecodecs/>`_
+ * `CPython 3.6.8, 3.7.7, 3.8.3 64-bit <https://www.python.org>`_
+ * `Numpy 1.16.6, 1.18.4 <https://www.numpy.org>`_
+ * `Imagecodecs 2020.5.30 <https://pypi.org/project/imagecodecs/>`_
(required only for encoding or decoding LZW, JPEG, etc.)
* `Matplotlib 3.1 <https://www.matplotlib.org>`_ (required only for plotting)
Revisions
---------
- 2020.5.11
+ 2020.6.3
Pass 2908 tests.
+ Support os.PathLike file names (#9).
+ 2020.5.30
+ Re-add pure Python PackBits decoder.
+ 2020.5.25
+ Make imagecodecs an optional dependency again.
+ Disable multi-threaded decoding of small LZW compressed segments.
+ Fix caching of TiffPage.decode function.
+ Fix xml.etree.cElementTree ImportError on Python 3.9.
+ Fix tostring DeprecationWarning.
+ 2020.5.11
Fix reading ImageJ grayscale mode RGB images (#6).
Remove napari reader plugin.
2020.5.7
@@ -208,10 +220,6 @@ Description: Read and write TIFF(r) files
Python 32-bit versions are deprecated.
- Update pip and setuptools to the latest version before installing tifffile:
-
- ``python -m pip install --upgrade pip setuptools``
-
Tifffile relies on the `imagecodecs <https://pypi.org/project/imagecodecs/>`_
package for encoding and decoding LZW, JPEG, and other compressed images.
@@ -273,6 +281,7 @@ Description: Read and write TIFF(r) files
<https://github.com/apeer-micro/apeer-ometiff-library>`_
* `Allen Institute for Cell Science imageio
<https://pypi.org/project/aicsimageio>`_
+ * `xtiff <https://github.com/BodenmillerGroup/xtiff>`_
References
----------
@@ -475,5 +484,6 @@ Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
Requires-Python: >=3.6
Provides-Extra: all
=====================================
README.rst
=====================================
@@ -38,23 +38,33 @@ For command line usage run ``python -m tifffile --help``
:License: BSD 3-Clause
-:Version: 2020.5.11
+:Version: 2020.6.3
Requirements
------------
This release has been tested with the following requirements and dependencies
(other versions may work):
-* `CPython 3.6.8, 3.7.7, 3.8.2 64-bit <https://www.python.org>`_
-* `Numpy 1.16.6 <https://www.numpy.org>`_
-* `Imagecodecs 2020.2.18 <https://pypi.org/project/imagecodecs/>`_
+* `CPython 3.6.8, 3.7.7, 3.8.3 64-bit <https://www.python.org>`_
+* `Numpy 1.16.6, 1.18.4 <https://www.numpy.org>`_
+* `Imagecodecs 2020.5.30 <https://pypi.org/project/imagecodecs/>`_
(required only for encoding or decoding LZW, JPEG, etc.)
* `Matplotlib 3.1 <https://www.matplotlib.org>`_ (required only for plotting)
Revisions
---------
-2020.5.11
+2020.6.3
Pass 2908 tests.
+ Support os.PathLike file names (#9).
+2020.5.30
+ Re-add pure Python PackBits decoder.
+2020.5.25
+ Make imagecodecs an optional dependency again.
+ Disable multi-threaded decoding of small LZW compressed segments.
+ Fix caching of TiffPage.decode function.
+ Fix xml.etree.cElementTree ImportError on Python 3.9.
+ Fix tostring DeprecationWarning.
+2020.5.11
Fix reading ImageJ grayscale mode RGB images (#6).
Remove napari reader plugin.
2020.5.7
@@ -200,10 +210,6 @@ Tested on little-endian platforms only.
Python 32-bit versions are deprecated.
-Update pip and setuptools to the latest version before installing tifffile:
-
- ``python -m pip install --upgrade pip setuptools``
-
Tifffile relies on the `imagecodecs <https://pypi.org/project/imagecodecs/>`_
package for encoding and decoding LZW, JPEG, and other compressed images.
@@ -265,6 +271,7 @@ Some libraries are using tifffile to write OME-TIFF files:
<https://github.com/apeer-micro/apeer-ometiff-library>`_
* `Allen Institute for Cell Science imageio
<https://pypi.org/project/aicsimageio>`_
+* `xtiff <https://github.com/BodenmillerGroup/xtiff>`_
References
----------
=====================================
setup.py
=====================================
@@ -57,19 +57,25 @@ setup(
long_description=readme,
author='Christoph Gohlke',
author_email='cgohlke at uci.edu',
- url='https://www.lfd.uci.edu/~gohlke/',
license='BSD',
+ url='https://www.lfd.uci.edu/~gohlke/',
+ project_urls={
+ 'Bug Tracker': 'https://github.com/cgohlke/tifffile/issues',
+ 'Source Code': 'https://github.com/cgohlke/tifffile',
+ # 'Documentation': 'https://',
+ },
packages=['tifffile'],
python_requires='>=3.6',
install_requires=[
'numpy>=1.15.1',
- 'imagecodecs>=2020.2.18',
+ # 'imagecodecs>=2020.2.18',
],
extras_require={
- 'all': ['matplotlib>=3.1'],
+ 'all': ['imagecodecs>=2020.2.18', 'matplotlib>=3.1'],
},
tests_require=[
- 'pytest', 'czifile', 'cmapfile', 'oiffile', 'lfdfiles', 'roifile'
+ 'pytest', 'imagecodecs', 'czifile', 'cmapfile', 'oiffile', 'lfdfiles',
+ 'roifile'
],
entry_points={
'console_scripts': [
@@ -89,5 +95,6 @@ setup(
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
+ 'Programming Language :: Python :: 3.9',
],
)
=====================================
tests/test_tifffile.py
=====================================
@@ -42,7 +42,7 @@ Private data files are not available due to size and copyright restrictions.
:License: BSD 3-Clause
-:Version: 2020.5.11
+:Version: 2020.6.3
"""
@@ -216,6 +216,9 @@ if not SKIP_CODECS:
import imagecodecs # noqa
except ImportError:
SKIP_CODECS = True
+ else:
+ if imagecodecs is None:
+ SKIP_CODECS = True
def config():
@@ -753,14 +756,45 @@ def test_issue_pathlib():
data = random_data('uint16', (219, 301))
with TempFileName('pathlib') as fname:
fname = pathlib.Path(fname)
+ assert isinstance(fname, os.PathLike)
+ # imwrite
imwrite(fname, data)
+ # imread
+ im = imread(fname)
+ assert_array_equal(im, data)
+ # memmap
+ im = memmap(fname)
+ try:
+ assert_array_equal(im, data)
+ finally:
+ del im
+ # TiffFile
with TiffFile(fname) as tif:
with TempFileName('pathlib_out') as outfname:
outfname = pathlib.Path(outfname)
+ # out=file
im = tif.asarray(out=outfname)
- assert isinstance(im, numpy.core.memmap)
- assert_array_equal(im, data)
- assert os.path.samefile(im.filename, str(outfname))
+ try:
+ assert isinstance(im, numpy.core.memmap)
+ assert_array_equal(im, data)
+ assert os.path.samefile(im.filename, str(outfname))
+ finally:
+ del im
+ # TiffSequence
+ with TiffSequence(fname) as tifs:
+ im = tifs.asarray()
+ assert_array_equal(im[0], data)
+ with TiffSequence([fname]) as tifs:
+ im = tifs.asarray()
+ assert_array_equal(im[0], data)
+
+ # TiffSequence container
+ if SKIP_PRIVATE or SKIP_CODECS:
+ pytest.skip(REASON)
+ fname = pathlib.Path(private_file('TiffSequence.zip'))
+ with TiffSequence('*.tif', container=fname, pattern=None) as tifs:
+ im = tifs.asarray()
+ assert im[9, 256, 256] == 135
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
@@ -9602,12 +9636,12 @@ def test_embed_mm_bytesio():
# Test sequence of image files
def test_sequence_stream_list():
- """Test TiffSequence with list of ByteIO streams raises ValueError."""
+ """Test TiffSequence with list of ByteIO streams raises TypeError."""
data = numpy.random.rand(7, 9)
files = [BytesIO(), BytesIO()]
for buffer in files:
imwrite(buffer, data)
- with pytest.raises(ValueError):
+ with pytest.raises(TypeError):
imread(files)
@@ -9685,16 +9719,16 @@ def test_sequence_leica_series():
def test_sequence_zip_container():
"""Test TiffSequence with glob pattern without axes pattern."""
fname = private_file('TiffSequence.zip')
- tifs = TiffSequence('*.tif', container=fname, pattern=None)
- assert len(tifs) == 10
- assert tifs.shape == (10,)
- assert tifs.axes == 'I'
- data = tifs.asarray()
- assert isinstance(data, numpy.ndarray)
- assert data.flags['C_CONTIGUOUS']
- assert data.shape == (10, 480, 640)
- assert data.dtype == 'uint8'
- assert data[9, 256, 256] == 135
+ with TiffSequence('*.tif', container=fname, pattern=None) as tifs:
+ assert len(tifs) == 10
+ assert tifs.shape == (10,)
+ assert tifs.axes == 'I'
+ data = tifs.asarray()
+ assert isinstance(data, numpy.ndarray)
+ assert data.flags['C_CONTIGUOUS']
+ assert data.shape == (10, 480, 640)
+ assert data.dtype == 'uint8'
+ assert data[9, 256, 256] == 135
@pytest.mark.skipif(
=====================================
tifffile.egg-info/PKG-INFO
=====================================
@@ -1,11 +1,13 @@
Metadata-Version: 2.1
Name: tifffile
-Version: 2020.5.11
+Version: 2020.6.3
Summary: Read and write TIFF(r) files
Home-page: https://www.lfd.uci.edu/~gohlke/
Author: Christoph Gohlke
Author-email: cgohlke at uci.edu
License: BSD
+Project-URL: Bug Tracker, https://github.com/cgohlke/tifffile/issues
+Project-URL: Source Code, https://github.com/cgohlke/tifffile
Description: Read and write TIFF(r) files
============================
@@ -46,23 +48,33 @@ Description: Read and write TIFF(r) files
:License: BSD 3-Clause
- :Version: 2020.5.11
+ :Version: 2020.6.3
Requirements
------------
This release has been tested with the following requirements and dependencies
(other versions may work):
- * `CPython 3.6.8, 3.7.7, 3.8.2 64-bit <https://www.python.org>`_
- * `Numpy 1.16.6 <https://www.numpy.org>`_
- * `Imagecodecs 2020.2.18 <https://pypi.org/project/imagecodecs/>`_
+ * `CPython 3.6.8, 3.7.7, 3.8.3 64-bit <https://www.python.org>`_
+ * `Numpy 1.16.6, 1.18.4 <https://www.numpy.org>`_
+ * `Imagecodecs 2020.5.30 <https://pypi.org/project/imagecodecs/>`_
(required only for encoding or decoding LZW, JPEG, etc.)
* `Matplotlib 3.1 <https://www.matplotlib.org>`_ (required only for plotting)
Revisions
---------
- 2020.5.11
+ 2020.6.3
Pass 2908 tests.
+ Support os.PathLike file names (#9).
+ 2020.5.30
+ Re-add pure Python PackBits decoder.
+ 2020.5.25
+ Make imagecodecs an optional dependency again.
+ Disable multi-threaded decoding of small LZW compressed segments.
+ Fix caching of TiffPage.decode function.
+ Fix xml.etree.cElementTree ImportError on Python 3.9.
+ Fix tostring DeprecationWarning.
+ 2020.5.11
Fix reading ImageJ grayscale mode RGB images (#6).
Remove napari reader plugin.
2020.5.7
@@ -208,10 +220,6 @@ Description: Read and write TIFF(r) files
Python 32-bit versions are deprecated.
- Update pip and setuptools to the latest version before installing tifffile:
-
- ``python -m pip install --upgrade pip setuptools``
-
Tifffile relies on the `imagecodecs <https://pypi.org/project/imagecodecs/>`_
package for encoding and decoding LZW, JPEG, and other compressed images.
@@ -273,6 +281,7 @@ Description: Read and write TIFF(r) files
<https://github.com/apeer-micro/apeer-ometiff-library>`_
* `Allen Institute for Cell Science imageio
<https://pypi.org/project/aicsimageio>`_
+ * `xtiff <https://github.com/BodenmillerGroup/xtiff>`_
References
----------
@@ -475,5 +484,6 @@ Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
Requires-Python: >=3.6
Provides-Extra: all
=====================================
tifffile.egg-info/requires.txt
=====================================
@@ -1,5 +1,5 @@
numpy>=1.15.1
-imagecodecs>=2020.2.18
[all]
+imagecodecs>=2020.2.18
matplotlib>=3.1
=====================================
tifffile/tifffile.py
=====================================
@@ -68,23 +68,33 @@ For command line usage run ``python -m tifffile --help``
:License: BSD 3-Clause
-:Version: 2020.5.11
+:Version: 2020.6.3
Requirements
------------
This release has been tested with the following requirements and dependencies
(other versions may work):
-* `CPython 3.6.8, 3.7.7, 3.8.2 64-bit <https://www.python.org>`_
-* `Numpy 1.16.6 <https://www.numpy.org>`_
-* `Imagecodecs 2020.2.18 <https://pypi.org/project/imagecodecs/>`_
+* `CPython 3.6.8, 3.7.7, 3.8.3 64-bit <https://www.python.org>`_
+* `Numpy 1.16.6, 1.18.4 <https://www.numpy.org>`_
+* `Imagecodecs 2020.5.30 <https://pypi.org/project/imagecodecs/>`_
(required only for encoding or decoding LZW, JPEG, etc.)
* `Matplotlib 3.1 <https://www.matplotlib.org>`_ (required only for plotting)
Revisions
---------
-2020.5.11
+2020.6.3
Pass 2908 tests.
+ Support os.PathLike file names (#9).
+2020.5.30
+ Re-add pure Python PackBits decoder.
+2020.5.25
+ Make imagecodecs an optional dependency again.
+ Disable multi-threaded decoding of small LZW compressed segments.
+ Fix caching of TiffPage.decode function.
+ Fix xml.etree.cElementTree ImportError on Python 3.9.
+ Fix tostring DeprecationWarning.
+2020.5.11
Fix reading ImageJ grayscale mode RGB images (#6).
Remove napari reader plugin.
2020.5.7
@@ -230,10 +240,6 @@ Tested on little-endian platforms only.
Python 32-bit versions are deprecated.
-Update pip and setuptools to the latest version before installing tifffile:
-
- ``python -m pip install --upgrade pip setuptools``
-
Tifffile relies on the `imagecodecs <https://pypi.org/project/imagecodecs/>`_
package for encoding and decoding LZW, JPEG, and other compressed images.
@@ -295,6 +301,7 @@ Some libraries are using tifffile to write OME-TIFF files:
<https://github.com/apeer-micro/apeer-ometiff-library>`_
* `Allen Institute for Cell Science imageio
<https://pypi.org/project/aicsimageio>`_
+* `xtiff <https://github.com/BodenmillerGroup/xtiff>`_
References
----------
@@ -489,7 +496,7 @@ Create a TIFF file from an iterator of tiles:
"""
-__version__ = '2020.5.11'
+__version__ = '2020.6.3'
__all__ = (
'imwrite',
@@ -541,7 +548,6 @@ import time
import json
import enum
import struct
-import pathlib
import warnings
import binascii
import datetime
@@ -570,7 +576,7 @@ def imread(files, **kwargs):
Parameters
----------
- files : str, binary stream, or sequence
+ files : str, path-like, binary stream, or sequence
File name, seekable binary stream, glob pattern, or sequence of
file names.
kwargs : dict
@@ -614,10 +620,14 @@ def imread(files, **kwargs):
files = glob.glob(files)
if not files:
raise ValueError('no files found')
- if not hasattr(files, 'seek') and len(files) == 1:
+ if (
+ not hasattr(files, 'seek') and
+ not isinstance(files, (str, os.PathLike)) and
+ len(files) == 1
+ ):
files = files[0]
- if isinstance(files, str) or hasattr(files, 'seek'):
+ if isinstance(files, (str, os.PathLike)) or hasattr(files, 'seek'):
with TiffFile(files, **kwargs_file) as tif:
return tif.asarray(**kwargs)
@@ -636,7 +646,7 @@ def imwrite(file, data=None, shape=None, dtype=None, **kwargs):
Parameters
----------
- file : str or binary stream
+ file : str, path-like, or binary stream
File name or writable binary stream, such as an open file or BytesIO.
data : array_like
Input image. The last dimensions are assumed to be image depth,
@@ -704,7 +714,7 @@ def memmap(filename, shape=None, dtype=None, page=None, series=0, mode='r+',
Parameters
----------
- filename : str
+ filename : str or path-like
Name of the TIFF file which stores the array.
shape : tuple
Shape of the empty array.
@@ -810,7 +820,7 @@ class TiffWriter:
Parameters
----------
- file : str, binary stream, or FileHandle
+ file : str, path-like, binary stream, or FileHandle
File name or writable binary stream, such as an open file
or BytesIO.
bigtiff : bool
@@ -1494,7 +1504,7 @@ class TiffWriter:
raise RuntimeError('value.size != count')
if value.dtype.char != dtype:
raise RuntimeError('value.dtype.char != dtype')
- ifdvalue = value.tostring()
+ ifdvalue = value.tobytes()
elif isinstance(value, (tuple, list)):
ifdvalue = pack(str(count) + dtype, *value)
else:
@@ -2139,7 +2149,7 @@ class TiffFile:
"""
def __init__(self, arg, name=None, offset=None, size=None, multifile=True,
- _useframes=None, **kwargs):
+ _useframes=None, _master=None, **kwargs):
"""Initialize instance from file.
Parameters
@@ -2185,6 +2195,8 @@ class TiffFile:
self._multifile = bool(multifile)
self._files = {fh.name: self} # cache of TiffFiles
self._decoders = {} # cache of TiffPage.decode functions
+ self._master = self if _master is None else _master
+
try:
fh.seek(0)
header = fh.read(4)
@@ -2739,7 +2751,8 @@ class TiffFile:
def _series_ome(self):
"""Return image series in OME-TIFF file(s)."""
- from xml.etree import cElementTree as etree # delayed import
+ from xml.etree import ElementTree as etree # delayed import
+
omexml = self.pages[0].description
try:
root = etree.fromstring(omexml)
@@ -2853,7 +2866,10 @@ class TiffFile:
return []
fname = uuid.attrib['FileName']
try:
- tif = TiffFile(os.path.join(dirname, fname))
+ tif = TiffFile(
+ os.path.join(dirname, fname),
+ _master=self
+ )
tif.pages.cache = True
tif.pages.useframes = True
tif.pages.keyframe = 0
@@ -4306,8 +4322,12 @@ class TiffPage:
Raises ValueError or NotImplementedError if decoding is not supported.
"""
- if self.hash in self.parent._decoders:
- return self.parent._decoders[self.hash]
+ if self.hash in self.parent._master._decoders:
+ return self.parent._master._decoders[self.hash]
+
+ def cache(decode):
+ self.parent._master._decoders[self.hash] = decode
+ return decode
if self.dtype is None:
def decode(*args, **kwargs):
@@ -4315,23 +4335,27 @@ class TiffPage:
f'TiffPage {self.index}: data type not supported: '
f'{self.sampleformat}{self.bitspersample}'
)
- return decode
+ return cache(decode)
- if self.compression not in TIFF.DECOMPESSORS:
- if imagecodecs is None:
- def decode(*args, **kwargs):
- raise ValueError(
- f'TiffPage {self.index}: '
- f'cannot decompress {self.compression.name}. '
- "The 'imagecodecs' package is not installed"
- )
+ try:
+ if self.compression == 1:
+ decompress = None
else:
- def decode(*args, **kwargs):
- raise ValueError(
- f'TiffPage {self.index}: '
- f'cannot decompress {self.compression.name}'
- )
- return decode
+ decompress = TIFF.DECOMPESSORS[self.compression]
+ except KeyError as exc:
+ def decode(*args, exc=str(exc)[1:-1], **kwargs):
+ raise ValueError(f'TiffPage {self.index}: {exc}')
+ return cache(decode)
+
+ try:
+ if self.predictor == 1:
+ unpredict = None
+ else:
+ unpredict = TIFF.UNPREDICTORS[self.predictor]
+ except KeyError as exc:
+ def decode(*args, exc=str(exc)[1:-1], **kwargs):
+ raise ValueError(f'TiffPage {self.index}: {exc}')
+ return cache(decode)
if self.tags.get(339) is not None:
tag = self.tags[339] # SampleFormat
@@ -4341,7 +4365,7 @@ class TiffPage:
f'TiffPage {self.index}: '
f'sample formats do not match {tag.value}'
)
- return decode
+ return cache(decode)
if (
self.is_subsampled and
@@ -4351,17 +4375,7 @@ class TiffPage:
raise NotImplementedError(
f'TiffPage {self.index}: chroma subsampling not supported'
)
- return decode
-
- if self.predictor == 1:
- unpredict = None
- else:
- unpredict = TIFF.UNPREDICTORS[self.predictor]
-
- if self.compression == 1:
- decompress = None
- else:
- decompress = TIFF.DECOMPESSORS[self.compression]
+ return cache(decode)
# normalize segments shape to [depth, length, height, contig]
if self.is_tiled:
@@ -4475,7 +4489,7 @@ class TiffPage:
f'TiffPage {self.index}: cannot decode JPEG '
f'with {self.bitspersample} bits per sample'
)
- return decode
+ return cache(decode)
if self.fillorder == 2:
log_warning(
@@ -4521,8 +4535,7 @@ class TiffPage:
data = reshape(data, index, shape)
return data, index, shape
- self.parent._decoders[self.hash] = decode
- return decode
+ return cache(decode)
dtype = numpy.dtype(self.parent.byteorder + self._dtype.char)
@@ -4580,8 +4593,7 @@ class TiffPage:
data = unpredict(data, axis=-2, out=data)
return data, index, shape
- self.parent._decoders[self.hash] = decode
- return decode
+ return cache(decode)
def segments(self, lock=None, maxworkers=None, func=None, sort=False):
"""Return iterator over decoded segments in TiffPage.
@@ -4744,6 +4756,7 @@ class TiffPage:
# decode individual strips or tiles
result = create_output(out, keyframe.shaped, keyframe._dtype)
out = result[0]
+ keyframe.decode # init TiffPage.decode function
def func(decoderesult, keyframe=keyframe, out=out):
# copy decoded segments to output array
@@ -4889,9 +4902,14 @@ class TiffPage:
@lazyattr
def maxworkers(self):
"""Return maximum number of threads for decoding strips or tiles."""
+ if self.is_contiguous:
+ return 1
if len(self._offsetscounts[0]) < 4:
return 1
if self.compression != 1 or self.fillorder != 1 or self.predictor != 1:
+ if self.compression == 5 and self._offsetscounts[1][0] < 8192:
+ # disable multi-threading for small LZW compressed segments
+ return 1
if imagecodecs is not None:
return min(TIFF.MAXWORKERS, len(self._offsetscounts[0]))
return 2 # optimum for large number of uncompressed tiles
@@ -6140,7 +6158,7 @@ class FileSequence:
fromfile : function or class
Array read function or class with asarray function returning numpy
array from single file.
- files : str, pathlib.Path, or sequence thereof
+ files : str, path-like, or sequence thereof
Glob filename pattern or sequence of file names. Default: \\*.
Binary streams are not supported.
container : str or container instance
@@ -6167,7 +6185,7 @@ class FileSequence:
self._container = container
if container:
import fnmatch
- if isinstance(container, str):
+ if isinstance(container, (str, os.PathLike)):
import zipfile
self._container = zipfile.ZipFile(container)
elif not hasattr(self._container, 'open'):
@@ -6176,23 +6194,16 @@ class FileSequence:
files = fnmatch.filter(self._container.namelist(), files)
if sort:
files = sort(files)
- else:
- if isinstance(files, pathlib.Path):
- files = str(files)
- if isinstance(files, str):
- files = glob.glob(files)
- if sort:
- files = sort(files)
- if not files:
- raise ValueError('no files found')
+ elif isinstance(files, os.PathLike):
+ files = [os.fspath(files)]
+ elif isinstance(files, str):
+ files = glob.glob(files)
+ if sort:
+ files = sort(files)
- files = list(files)
+ files = [os.fspath(f) for f in files]
if not files:
raise ValueError('no files found')
- if isinstance(files[0], pathlib.Path):
- files = [str(pathlib.Path(f)) for f in files]
- elif not isinstance(files[0], str):
- raise ValueError('not a file name')
if hasattr(fromfile, 'asarray'):
# redefine fromfile to use asarray from fromfile class
@@ -6380,7 +6391,7 @@ class FileHandle:
Parameters
----------
- file : str, pathlib.Path, binary stream, or FileHandle
+ file : str, path-like, binary stream, or FileHandle
File name or seekable binary stream, such as an open file
or BytesIO.
mode : str
@@ -6412,8 +6423,8 @@ class FileHandle:
if self._fh:
return # file is open
- if isinstance(self._file, pathlib.Path):
- self._file = str(self._file)
+ if isinstance(self._file, os.PathLike):
+ self._file = os.fspath(self._file)
if isinstance(self._file, str):
# file name
self._file = os.path.realpath(self._file)
@@ -6654,7 +6665,7 @@ class FileHandle:
data.tofile(self._fh)
except Exception:
# BytesIO
- self._fh.write(data.tostring())
+ self._fh.write(data.tobytes())
def tell(self):
"""Return file's current position."""
@@ -6836,6 +6847,8 @@ class Timer:
i = 0
while i < len(s) and s[i:i + 2] in '0:0010203040506070809':
i += 1
+ if s[i:i + 1] == ':':
+ i += 1
return f'{s[i:]} s'
def __enter__(self):
@@ -8152,14 +8165,18 @@ class TIFF:
def __getitem__(self, key):
if key in self._codecs:
return self._codecs[key]
- if imagecodecs is None:
- raise KeyError(key)
- if key == 2:
- codec = imagecodecs.delta_encode
- elif key == 3:
- codec = imagecodecs.floatpred_encode
- else:
- raise KeyError(key)
+ try:
+ if key == 2:
+ codec = imagecodecs.delta_encode
+ elif key == 3:
+ codec = imagecodecs.floatpred_encode
+ else:
+ raise KeyError(f'{key} is not a valid PREDICTOR')
+ except AttributeError:
+ raise KeyError(
+ f'{TIFF.PREDICTOR(key)!r}'
+ " requires the 'imagecodecs' package"
+ )
self._codecs[key] = codec
return codec
@@ -8177,14 +8194,18 @@ class TIFF:
def __getitem__(self, key):
if key in self._codecs:
return self._codecs[key]
- if imagecodecs is None:
- raise KeyError(key)
- if key == 2:
- codec = imagecodecs.delta_decode
- elif key == 3:
- codec = imagecodecs.floatpred_decode
- else:
- raise KeyError(key)
+ try:
+ if key == 2:
+ codec = imagecodecs.delta_decode
+ elif key == 3:
+ codec = imagecodecs.floatpred_decode
+ else:
+ raise KeyError(f'{key} is not a valid PREDICTOR')
+ except AttributeError:
+ raise KeyError(
+ f'{TIFF.PREDICTOR(key)!r}'
+ " requires the 'imagecodecs' package"
+ )
self._codecs[key] = codec
return codec
@@ -8204,32 +8225,40 @@ class TIFF:
def __getitem__(self, key):
if key in self._codecs:
return self._codecs[key]
- if imagecodecs is None:
- raise KeyError(key)
- if key == 5:
- codec = imagecodecs.lzw_encode
- elif key == 7:
- codec = imagecodecs.jpeg_encode
- elif key == 8 or key == 32946:
- codec = imagecodecs.zlib_encode
- elif key == 32773:
- codec = imagecodecs.packbits_encode
- elif key == 34712:
- codec = imagecodecs.jpeg2k_encode
- elif key == 34887:
- codec = imagecodecs.lerc_encode
- elif key == 34925:
- codec = imagecodecs.lzma_encode
- elif key == 34933:
- codec = imagecodecs.png_encode
- elif key == 34934:
- codec = imagecodecs.jpegxr_encode
- elif key == 50000:
- codec = imagecodecs.zstd_encode
- elif key == 50001:
- codec = imagecodecs.webp_encode
- else:
- raise KeyError(key)
+ try:
+ if key == 5:
+ codec = imagecodecs.lzw_encode
+ elif key == 7:
+ codec = imagecodecs.jpeg_encode
+ elif key == 8 or key == 32946:
+ codec = imagecodecs.zlib_encode
+ elif key == 32773:
+ codec = imagecodecs.packbits_encode
+ elif key == 34712:
+ codec = imagecodecs.jpeg2k_encode
+ elif key == 34887:
+ codec = imagecodecs.lerc_encode
+ elif key == 34925:
+ codec = imagecodecs.lzma_encode
+ elif key == 34933:
+ codec = imagecodecs.png_encode
+ elif key == 34934:
+ codec = imagecodecs.jpegxr_encode
+ elif key == 50000:
+ codec = imagecodecs.zstd_encode
+ elif key == 50001:
+ codec = imagecodecs.webp_encode
+ else:
+ try:
+ msg = f'{TIFF.COMPRESSION(key)!r} not supported'
+ except ValueError:
+ msg = f'{key} is not a valid COMPRESSION'
+ raise KeyError(msg)
+ except AttributeError:
+ raise KeyError(
+ f'{TIFF.COMPRESSION(key)!r} '
+ "requires the 'imagecodecs' package"
+ )
self._codecs[key] = codec
return codec
@@ -8243,40 +8272,49 @@ class TIFF:
self._codecs = {None: identityfunc, 1: identityfunc}
if imagecodecs is None:
self._codecs[8] = zlib_decode
+ self._codecs[32773] = packbits_decode
self._codecs[32946] = zlib_decode
self._codecs[34925] = lzma_decode
def __getitem__(self, key):
if key in self._codecs:
return self._codecs[key]
- if imagecodecs is None:
- raise KeyError(key)
- if key == 5:
- codec = imagecodecs.lzw_decode
- elif key == 6 or key == 7:
- codec = imagecodecs.jpeg_decode
- elif key == 8 or key == 32946:
- codec = imagecodecs.zlib_decode
- elif key == 32773:
- codec = imagecodecs.packbits_decode
- # elif key == 34892:
- # codec = imagecodecs.jpeg_decode # DNG lossy
- elif key == 33003 or key == 33005 or key == 34712:
- codec = imagecodecs.jpeg2k_decode
- elif key == 34887:
- codec = imagecodecs.lerc_decode
- elif key == 34925:
- codec = imagecodecs.lzma_decode
- elif key == 34933:
- codec = imagecodecs.png_decode
- elif key == 34934:
- codec = imagecodecs.jpegxr_decode
- elif key == 50000 or key == 34926: # 34926 deprecated
- codec = imagecodecs.zstd_decode
- elif key == 50001 or key == 34927: # 34927 deprecated
- codec = imagecodecs.webp_decode
- else:
- raise KeyError(key)
+ try:
+ if key == 5:
+ codec = imagecodecs.lzw_decode
+ elif key == 6 or key == 7:
+ codec = imagecodecs.jpeg_decode
+ elif key == 8 or key == 32946:
+ codec = imagecodecs.zlib_decode
+ elif key == 32773:
+ codec = imagecodecs.packbits_decode
+ # elif key == 34892:
+ # codec = imagecodecs.jpeg_decode # DNG lossy
+ elif key == 33003 or key == 33005 or key == 34712:
+ codec = imagecodecs.jpeg2k_decode
+ elif key == 34887:
+ codec = imagecodecs.lerc_decode
+ elif key == 34925:
+ codec = imagecodecs.lzma_decode
+ elif key == 34933:
+ codec = imagecodecs.png_decode
+ elif key == 34934:
+ codec = imagecodecs.jpegxr_decode
+ elif key == 50000 or key == 34926: # 34926 deprecated
+ codec = imagecodecs.zstd_decode
+ elif key == 50001 or key == 34927: # 34927 deprecated
+ codec = imagecodecs.webp_decode
+ else:
+ try:
+ msg = f'{TIFF.COMPRESSION(key)!r} not supported'
+ except ValueError:
+ msg = f'{key} is not a valid COMPRESSION'
+ raise KeyError(msg)
+ except AttributeError:
+ raise KeyError(
+ f'{TIFF.COMPRESSION(key)!r} '
+ "requires the 'imagecodecs' package"
+ )
self._codecs[key] = codec
return codec
@@ -9852,7 +9890,7 @@ def read_tvips_header(fh, byteorder, dtype, count, offsetsize):
# decode utf16 strings
for name, typestr in TIFF.TVIPS_HEADER_V2:
if typestr.startswith('V'):
- s = header[name].tostring().decode('utf-16', errors='ignore')
+ s = header[name].tobytes().decode('utf-16', errors='ignore')
result[name] = stripnull(s, null='\0')
else:
result[name] = header[name].tolist()
@@ -10513,7 +10551,7 @@ def metaseries_description_metadata(description):
if not description.startswith('<MetaData>'):
raise ValueError('invalid MetaSeries image description')
- from xml.etree import cElementTree as etree # delayed import
+ from xml.etree import ElementTree as etree # delayed import
root = etree.fromstring(description)
types = {
@@ -10861,6 +10899,38 @@ if imagecodecs is None:
f'to {numpy.dtype(dtype)} not supported'
)
+ def packbits_decode(encoded, out=None):
+ r"""Decompress PackBits encoded byte string.
+
+ >>> packbits_decode(b'\x80\x80') # NOP
+ b''
+ >>> packbits_decode(b'\x02123')
+ b'123'
+ >>> packbits_decode(
+ ... b'\xfe\xaa\x02\x80\x00\x2a\xfd\xaa\x03\x80\x00\x2a\x22\xf7\xaa'
+ ... )[:-5]
+ b'\xaa\xaa\xaa\x80\x00*\xaa\xaa\xaa\xaa\x80\x00*"\xaa\xaa\xaa\xaa\xaa'
+
+ """
+ out = []
+ out_extend = out.extend
+ i = 0
+ try:
+ while True:
+ n = ord(encoded[i:i + 1]) + 1
+ i += 1
+ if n > 129:
+ # replicate
+ out_extend(encoded[i:i + 1] * (258 - n))
+ i += 1
+ elif n < 129:
+ # literal
+ out_extend(encoded[i:i + n])
+ i += n
+ except TypeError:
+ pass
+ return bytes(out)
+
else:
bitorder_decode = imagecodecs.bitorder_decode # noqa
packints_decode = imagecodecs.packints_decode # noqa
@@ -11218,39 +11288,36 @@ def stack_pages(pages, out=None, maxworkers=None, **kwargs):
dtype = page0.dtype
out = create_output(out, shape, dtype)
- page_maxworkers = 1
+ # TODO: benchmark and optimize this
if maxworkers is None or maxworkers < 1:
# auto-detect
- maxworkers = TIFF.MAXWORKERS
- if maxworkers == 1:
- kwargs['maxworkers'] = 1
+ page_maxworkers = page0.maxworkers
+ maxworkers = min(npages, TIFF.MAXWORKERS)
+ if maxworkers == 1 or page0.is_contiguous:
+ maxworkers = page_maxworkers = 1
elif npages < 3:
maxworkers = 1
+ elif (
+ page_maxworkers <= 2 and
+ page0.compression == 1 and
+ page0.fillorder == 1 and
+ page0.predictor == 1
+ ):
+ maxworkers = 1
+ elif page0.compression == 5 and page0._offsetscounts[1][0] < 8192:
+ # disable for small LZW compressed segments
+ maxworkers = page_maxworkers = 1
else:
- # TODO: optimize this
- page_maxworkers = page0.maxworkers
- kwargs['maxworkers'] = page_maxworkers
- if (
- page_maxworkers <= 2 and
- page0.compression == 1 and
- page0.fillorder == 1 and
- page0.predictor == 1
- ):
- # multi-threading not worth
- maxworkers = 1
- elif page_maxworkers > 2:
- maxworkers = max(maxworkers - page_maxworkers, 1)
+ page_maxworkers = 1
elif maxworkers == 1:
- # disable
- kwargs['maxworkers'] = 1
+ maxworkers = page_maxworkers = 1
+ elif npages > maxworkers or page0.maxworkers < 2:
+ page_maxworkers = 1
else:
- # prefer parallel decoding of tiles or stripes
- # use remaining threads for parallel decoding of pages
- page_maxworkers = page0.maxworkers
- kwargs['maxworkers'] = page_maxworkers
- if page_maxworkers > 1:
- maxworkers = max(maxworkers - page_maxworkers, 1)
+ page_maxworkers = maxworkers
+ maxworkers = 1
+ kwargs['maxworkers'] = page_maxworkers
page0.parent.filehandle.lock = maxworkers > 1 or page_maxworkers > 1
filecache = OpenFileCache(size=max(4, maxworkers),
@@ -11268,6 +11335,7 @@ def stack_pages(pages, out=None, maxworkers=None, **kwargs):
for i, page in enumerate(pages):
func(page, i)
else:
+ page0.decode # init TiffPage.decode function
with ThreadPoolExecutor(maxworkers) as executor:
for _ in executor.map(func, pages, range(npages)):
pass
@@ -11311,8 +11379,6 @@ def create_output(out, shape, dtype, mode='w+', suffix=None):
if not numpy.can_cast(dtype, out.dtype):
raise ValueError('incompatible output dtype')
return out.reshape(shape)
- if isinstance(out, pathlib.Path):
- out = str(out)
return numpy.memmap(out, shape=shape, dtype=dtype, mode=mode)
@@ -11717,7 +11783,7 @@ def xml2dict(xml, sanitize=True, prefix=None):
{'level1': {'level2': 3.5322}}
"""
- from xml.etree import cElementTree as etree # delayed import
+ from xml.etree import ElementTree as etree # delayed import
at = tx = ''
if prefix:
View it on GitLab: https://salsa.debian.org/python-team/modules/tifffile/-/commit/c3951b7521d4022a8306736820729794b84e15eb
--
View it on GitLab: https://salsa.debian.org/python-team/modules/tifffile/-/commit/c3951b7521d4022a8306736820729794b84e15eb
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20200612/7ba22499/attachment-0001.html>
More information about the debian-med-commit
mailing list