Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-tifffile for openSUSE:Factory
checked in at 2023-06-01 17:19:31
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-tifffile (Old)
and /work/SRC/openSUSE:Factory/.python-tifffile.new.2531 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-tifffile"
Thu Jun 1 17:19:31 2023 rev:12 rq:1090095 version:2023.4.12
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-tifffile/python-tifffile.changes
2023-05-25 23:52:33.395617983 +0200
+++
/work/SRC/openSUSE:Factory/.python-tifffile.new.2531/python-tifffile.changes
2023-06-01 17:19:39.134207279 +0200
@@ -1,0 +2,15 @@
+Wed May 31 08:27:38 UTC 2023 - Dirk Müller <[email protected]>
+
+- update to 2023.4.12:
+ * Pass 4988 tests.
+ * Do not write duplicate ImageDescription tags from extratags
+ (breaking).
+ * Support multifocal SVS files (#193).
+ * Log warning when filtering out extratags.
+ * Fix writing OME-TIFF with image description in extratags.
+ * Ignore invalid predictor tag value if prediction is not used.
+ * Raise KeyError if ZarrStore is missing requested chunk.
+ * 2023.3.21
+ * Fix reading MMstack with missing data (#187).
+
+-------------------------------------------------------------------
Old:
----
tifffile-2023.3.15.tar.gz
New:
----
tifffile-2023.4.12.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-tifffile.spec ++++++
--- /var/tmp/diff_new_pack.mVSmGg/_old 2023-06-01 17:19:39.850211523 +0200
+++ /var/tmp/diff_new_pack.mVSmGg/_new 2023-06-01 17:19:39.858211571 +0200
@@ -25,7 +25,7 @@
%bcond_with test
%endif
Name: python-tifffile%{psuffix}
-Version: 2023.3.15
+Version: 2023.4.12
Release: 0
Summary: Read and write TIFF files
License: BSD-2-Clause
@@ -127,6 +127,7 @@
donttest="$donttest or test_write_extrasamples_planar"
donttest="$donttest or test_write_extrasamples_contig_rgb"
donttest="$donttest or test_write_compression_args"
+donttest="$donttest or test_issue_invalid_predictor"
%pytest -n auto -k "not ($donttest)"
%endif
++++++ tifffile-2023.3.15.tar.gz -> tifffile-2023.4.12.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tifffile-2023.3.15/CHANGES.rst
new/tifffile-2023.4.12/CHANGES.rst
--- old/tifffile-2023.3.15/CHANGES.rst 2023-03-15 23:42:04.000000000 +0100
+++ new/tifffile-2023.4.12/CHANGES.rst 2023-04-13 02:13:08.000000000 +0200
@@ -1,9 +1,22 @@
Revisions
---------
+2023.4.12
+
+- Pass 4988 tests.
+- Do not write duplicate ImageDescription tags from extratags (breaking).
+- Support multifocal SVS files (#193).
+- Log warning when filtering out extratags.
+- Fix writing OME-TIFF with image description in extratags.
+- Ignore invalid predictor tag value if prediction is not used.
+- Raise KeyError if ZarrStore is missing requested chunk.
+
+2023.3.21
+
+- Fix reading MMstack with missing data (#187).
+
2023.3.15
-- Pass 4980 tests.
- Fix corruption using tile generators with prediction/compression (#185).
- Add parser for Micro-Manager MMStack series (breaking).
- Return micromanager_metadata IndexMap as numpy array (breaking).
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tifffile-2023.3.15/README.rst
new/tifffile-2023.4.12/README.rst
--- old/tifffile-2023.3.15/README.rst 2023-03-15 23:42:04.000000000 +0100
+++ new/tifffile-2023.4.12/README.rst 2023-04-13 02:13:08.000000000 +0200
@@ -30,7 +30,7 @@
:Author: `Christoph Gohlke <https://www.cgohlke.com>`_
:License: BSD 3-Clause
-:Version: 2023.3.15
+:Version: 2023.4.12
:DOI: `10.5281/zenodo.6795860 <https://doi.org/10.5281/zenodo.6795860>`_
Quickstart
@@ -66,9 +66,9 @@
This revision was tested with the following requirements and dependencies
(other versions may work):
-- `CPython <https://www.python.org>`_ 3.8.10, 3.9.13, 3.10.10, 3.11.2, 64-bit
+- `CPython <https://www.python.org>`_ 3.8.10, 3.9.13, 3.10.11, 3.11.3, 64-bit
- `NumPy <https://pypi.org/project/numpy/>`_ 1.23.5
-- `Imagecodecs <https://pypi.org/project/imagecodecs/>`_ 2023.1.23
+- `Imagecodecs <https://pypi.org/project/imagecodecs/>`_ 2023.3.16
(required for encoding or decoding LZW, JPEG, etc. compressed segments)
- `Matplotlib <https://pypi.org/project/matplotlib/>`_ 3.7.1
(required for plotting)
@@ -76,15 +76,28 @@
(required only for validating and printing XML)
- `Zarr <https://pypi.org/project/zarr/>`_ 2.14.2
(required only for opening Zarr stores)
-- `Fsspec <https://pypi.org/project/fsspec/>`_ 2023.3.0
+- `Fsspec <https://pypi.org/project/fsspec/>`_ 2023.4.0
(required only for opening ReferenceFileSystem files)
Revisions
---------
+2023.4.12
+
+- Pass 4988 tests.
+- Do not write duplicate ImageDescription tags from extratags (breaking).
+- Support multifocal SVS files (#193).
+- Log warning when filtering out extratags.
+- Fix writing OME-TIFF with image description in extratags.
+- Ignore invalid predictor tag value if prediction is not used.
+- Raise KeyError if ZarrStore is missing requested chunk.
+
+2023.3.21
+
+- Fix reading MMstack with missing data (#187).
+
2023.3.15
-- Pass 4980 tests.
- Fix corruption using tile generators with prediction/compression (#185).
- Add parser for Micro-Manager MMStack series (breaking).
- Return micromanager_metadata IndexMap as numpy array (breaking).
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tifffile-2023.3.15/tests/test_tifffile.py
new/tifffile-2023.4.12/tests/test_tifffile.py
--- old/tifffile-2023.3.15/tests/test_tifffile.py 2023-03-15
23:42:04.000000000 +0100
+++ new/tifffile-2023.4.12/tests/test_tifffile.py 2023-04-13
02:13:08.000000000 +0200
@@ -37,7 +37,7 @@
Public data files can be requested from the author.
Private data files are not available due to size and copyright restrictions.
-:Version: 2023.3.15
+:Version: 2023.4.12
"""
@@ -1724,8 +1724,8 @@
[[0]],
description='1st description',
extratags=[
- (270, 1, None, b'\1\128\0', True),
- (270, 1, None, b'\2\128\0', True),
+ ('ImageDescription', 1, None, b'\1\128\0', True),
+ ('ImageDescription', 1, None, b'\2\128\0', True),
],
metadata=False,
)
@@ -2481,7 +2481,9 @@
if compression == 'none' and predictor != 'none':
pytest.xfail('cannot use predictor without compression')
- data = numpy.empty((32, 32, samples) if samples else (32, 32), numpy.uint8)
+ data = numpy.empty(
+ (27, 23, samples) if samples else (27, 23, 1), numpy.uint8
+ )
data[:] = 199
data[7:9, 11:13] = 13
data[22:25, 19:22] = 11
@@ -2504,14 +2506,51 @@
compression=compression,
predictor=predictor,
)
- assert_array_equal(imread(fname), data[:27, :23].squeeze())
+ assert_array_equal(imread(fname), data.squeeze())
if (
imagecodecs is None
or not imagecodecs.TIFF
or (compression == 'packbits' and predictor == 'horizontal')
):
return
- assert_array_equal(imagecodecs.imread(fname), data[:27, :23].squeeze())
+ assert_array_equal(imagecodecs.imread(fname), data.squeeze())
+
+
+def test_issue_extratags_filter(caplog):
+ """Test filtering extratags."""
+ # https://github.com/cgohlke/tifffile/pull/188
+ with TempFileName('extratags_filter') as fname:
+ imwrite(
+ fname,
+ shape=(10, 10),
+ dtype='u1',
+ extratags=[
+ (322, 3, 1, 2, False), # TileWidth is filtered
+ (34665, 13, 1, 0, False), # ExifIFD is filtered
+ (270, 2, 0, 'second description', True), # filtered
+ ('FillOrder', 3, 1, 1, True), # by name should go through
+ ],
+ )
+ assert 'extratag 322' in caplog.text
+ assert 'extratag 34665' in caplog.text
+ with TiffFile(fname) as tif:
+ tags = tif.pages.first.tags
+ assert 322 not in tags
+ assert 34665 not in tags
+ assert tags.get(270, index=1) is None
+ assert tags[266].value == 1
+
+
+def test_issue_invalid_predictor(caplog):
+ """Test decoding JPEG compression with invalid predictor tag."""
+ fname = private_file('issues/invalid_predictor.tiff')
+ with TiffFile(fname) as tif:
+ page = tif.pages.first
+ assert page.predictor == 58240
+ assert page.compression == 7
+ data = page.asarray()
+ assert 'ignoring predictor' in caplog.text
+ assert data.shape == (1275, 1650, 4)
class TestExceptions:
@@ -11924,6 +11963,7 @@
assert meta['DisplaySettings'][0]['Name'] == 'Dual-GFP'
# assert series properties
series = tif.series[0]
+ assert series[-1] is None # missing page
assert len(series) == 126
assert series.shape == (63, 2, 264, 320)
assert series.axes == 'TCYX'
@@ -11935,7 +11975,14 @@
assert data.shape == (63, 2, 264, 320)
assert data.dtype == numpy.uint16
assert data[59, 1, 151, 186] == 599
- assert_aszarr_method(series, data)
+ # assert zarr
+ if not SKIP_ZARR and zarr is not None:
+ with series.aszarr(fillvalue=100) as store:
+ assert '1.1.0.0' in store
+ assert '62.1.0.0' not in store # missing page
+ z = zarr.open(store, mode='r')
+ assert z[62, 1, 0, 0] == 100
+ assert_array_equal(data[:62], z[:62])
# test OME and ImageJ
assert_array_equal(data, imread(fname, is_mmstack=False))
assert_array_equal(data, imread(fname, is_mmstack=False, is_ome=False))
@@ -11987,6 +12034,50 @@
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_LARGE, reason=REASON)
+def test_read_mmstack_missing_sbs(caplog):
+ """Test read MicroManager dataset with missing data."""
+ # https://github.com/cgohlke/tifffile/issues/187
+ fname = private_file('MMStack/10X_c1-SBS-1_A1_Tile-102.sbs.tif')
+ with TiffFile(fname) as tif:
+ assert tif.is_micromanager
+ assert tif.is_mmstack
+ assert tif.is_ome
+ assert tif.is_imagej
+ assert not tif.is_ndtiff
+ assert tif.byteorder == '<'
+ assert len(tif.pages) == 5
+ assert len(tif.series) == 1
+ assert 'MMStack file name is invalid' in caplog.text
+ assert 'MMStack series is missing files' in caplog.text
+ # assert metadata
+ meta = tif.micromanager_metadata
+ assert meta is not None
+ assert meta['MajorVersion'] == 0
+ assert meta['Summary']['MicroManagerVersion'].startswith('1.4.23 2019')
+ assert meta['Summary']['Prefix'] == '10X_c1-SBS-1_1'
+ assert meta['IndexMap'].shape == (5, 5)
+ assert meta['Comments']['Summary'] == ''
+ assert meta['DisplaySettings'][0]['Name'] == 'DAPI_10p'
+ # assert series properties
+ series = tif.series[0]
+ assert len(series) == 5
+ assert series.shape == (5, 1024, 1024)
+ assert series.axes == 'CYX'
+ assert series.kind == 'mmstack'
+ assert not series.is_multifile
+ # assert data
+ data = tif.asarray()
+ assert isinstance(data, numpy.ndarray)
+ assert data.shape == (5, 1024, 1024)
+ assert data.dtype == numpy.uint16
+ assert data[3, 151, 186] == 542
+ assert_aszarr_method(series, data)
+ # test OME
+ assert_array_equal(data, imread(fname, is_mmstack=False))
+ assert__str__(tif)
+
+
[email protected](SKIP_PRIVATE or SKIP_LARGE, reason=REASON)
def test_read_mmstack_trzc():
"""Test read MicroManager 6 dimensional dataset."""
fname = private_file(
@@ -13398,7 +13489,7 @@
description = 'Created by TestTiffWriter\nLorem ipsum dolor...'
pagename = 'Page name'
extratags = [
- (270, 's', 0, description, True),
+ ('ImageDescription', 's', 0, description, True),
('PageName', 's', 0, pagename, False),
(50001, 'b', 1, b'1', True),
(50002, 'b', 2, b'12', True),
@@ -13537,6 +13628,20 @@
assert__str__(tif)
+def test_write_software_tag():
+ """Test write Software tag."""
+ data = random_data(numpy.uint8, (2, 219, 301))
+ software = 'test_tifffile.py'
+ with TempFileName('software_tag') as fname:
+ imwrite(fname, data, software=software)
+ assert_valid_tiff(fname)
+ with TiffFile(fname) as tif:
+ assert len(tif.pages) == 2
+ assert tif.pages.first.software == software
+ assert 'Software' not in tif.pages[1].tags
+ assert__str__(tif)
+
+
def test_write_description_tag():
"""Test write two description tags."""
data = random_data(numpy.uint8, (2, 219, 301))
@@ -13588,18 +13693,107 @@
assert__str__(tif)
-def test_write_software_tag():
- """Test write Software tag."""
- data = random_data(numpy.uint8, (2, 219, 301))
- software = 'test_tifffile.py'
- with TempFileName('software_tag') as fname:
- imwrite(fname, data, software=software)
- assert_valid_tiff(fname)
+def test_write_description_ome():
+ """Test write multiple imagedescription tags to OME."""
+ # https://forum.image.sc/t/79471
+ with TempFileName('description_ome') as fname:
+ with pytest.warns(UserWarning):
+ imwrite(
+ fname,
+ shape=(2, 32, 32),
+ dtype='uint8',
+ ome=True,
+ description='description', # not written
+ extratags=[('ImageDescription', 2, None, 'extratags', False)],
+ )
with TiffFile(fname) as tif:
- assert len(tif.pages) == 2
- assert tif.pages.first.software == software
- assert 'Software' not in tif.pages[1].tags
- assert__str__(tif)
+ assert tif.is_ome
+ page = tif.pages.first
+ assert page.description.startswith('<?xml')
+ assert page.description1 == 'extratags'
+ assert tif.pages[1].description == 'extratags'
+
+
+def test_write_description_imagej():
+ """Test write multiple imagedescription tags."""
+ with TempFileName('description_imagej') as fname:
+ with pytest.warns(UserWarning):
+ imwrite(
+ fname,
+ shape=(2, 32, 32),
+ dtype='uint8',
+ imagej=True,
+ description='description', # not written
+ extratags=[('ImageDescription', 2, None, 'extratags', False)],
+ )
+ with TiffFile(fname) as tif:
+ assert tif.is_imagej
+ page = tif.pages.first
+ assert page.description.startswith('ImageJ=')
+ assert page.description1 == 'extratags'
+ assert tif.pages[1].description == 'extratags'
+
+
+def test_write_description_shaped():
+ """Test write multiple imagedescription tags to shaped."""
+ with TempFileName('description_shaped') as fname:
+ imwrite(
+ fname,
+ shape=(2, 32, 32),
+ dtype='uint8',
+ description='description', # written
+ extratags=[('ImageDescription', 2, None, 'extratags', False)],
+ )
+ with TiffFile(fname) as tif:
+ assert tif.is_shaped
+ page = tif.pages.first
+ assert page.description == 'description'
+ assert page.description1.startswith('{')
+ assert page.tags.getall(270)[2].value == 'extratags'
+ assert tif.pages[1].description == 'extratags'
+
+
+def test_write_description_overwrite():
+ """Test overwrite imagedescription tag."""
+ with TempFileName('description_overwrite') as fname:
+ with TiffWriter(fname) as tif:
+ tif.write(
+ shape=(2, 32, 32),
+ dtype='uint8',
+ description='description', # overwritten
+ extratags=[('ImageDescription', 2, None, 'extratags', False)],
+ metadata=None,
+ )
+ tif.overwrite_description('overwritten description')
+ with TiffFile(fname) as tif:
+ assert not tif.is_shaped
+ page = tif.pages.first
+ assert page.description == 'overwritten description'
+ assert page.description1 == 'extratags'
+ assert tif.pages[1].description == 'extratags'
+
+
+def test_write_description_extratags():
+ """Test write imagedescription tags using extratag."""
+ with TempFileName('description_extratags') as fname:
+ with TiffWriter(fname) as tif:
+ tif.write(
+ shape=(2, 32, 32),
+ dtype='uint8',
+ extratags=[
+ (270, 2, None, 'description 0', False),
+ ('ImageDescription', 2, None, 'description 1', False),
+ ],
+ metadata=None,
+ )
+ with TiffFile(fname) as tif:
+ assert not tif.is_shaped
+ page = tif.pages.first
+ assert page.description == 'description 0'
+ assert page.description1 == 'description 1'
+ page = tif.pages[1]
+ assert page.description == 'description 0'
+ assert page.description1 == 'description 1'
def test_write_resolution_float():
@@ -18253,7 +18447,7 @@
import turbojpeg
from opentile.geometry import Point
- from opentile.ndpi_tiler import NdpiTiler
+ from opentile.formats import NdpiTiler
except ImportError:
pytest.skip('opentile missing')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tifffile-2023.3.15/tifffile/tifffile.py
new/tifffile-2023.4.12/tifffile/tifffile.py
--- old/tifffile-2023.3.15/tifffile/tifffile.py 2023-03-15 23:42:04.000000000
+0100
+++ new/tifffile-2023.4.12/tifffile/tifffile.py 2023-04-13 02:13:08.000000000
+0200
@@ -60,7 +60,7 @@
:Author: `Christoph Gohlke <https://www.cgohlke.com>`_
:License: BSD 3-Clause
-:Version: 2023.3.15
+:Version: 2023.4.12
:DOI: `10.5281/zenodo.6795860 <https://doi.org/10.5281/zenodo.6795860>`_
Quickstart
@@ -96,9 +96,9 @@
This revision was tested with the following requirements and dependencies
(other versions may work):
-- `CPython <https://www.python.org>`_ 3.8.10, 3.9.13, 3.10.10, 3.11.2, 64-bit
+- `CPython <https://www.python.org>`_ 3.8.10, 3.9.13, 3.10.11, 3.11.3, 64-bit
- `NumPy <https://pypi.org/project/numpy/>`_ 1.23.5
-- `Imagecodecs <https://pypi.org/project/imagecodecs/>`_ 2023.1.23
+- `Imagecodecs <https://pypi.org/project/imagecodecs/>`_ 2023.3.16
(required for encoding or decoding LZW, JPEG, etc. compressed segments)
- `Matplotlib <https://pypi.org/project/matplotlib/>`_ 3.7.1
(required for plotting)
@@ -106,15 +106,28 @@
(required only for validating and printing XML)
- `Zarr <https://pypi.org/project/zarr/>`_ 2.14.2
(required only for opening Zarr stores)
-- `Fsspec <https://pypi.org/project/fsspec/>`_ 2023.3.0
+- `Fsspec <https://pypi.org/project/fsspec/>`_ 2023.4.0
(required only for opening ReferenceFileSystem files)
Revisions
---------
+2023.4.12
+
+- Pass 4988 tests.
+- Do not write duplicate ImageDescription tags from extratags (breaking).
+- Support multifocal SVS files (#193).
+- Log warning when filtering out extratags.
+- Fix writing OME-TIFF with image description in extratags.
+- Ignore invalid predictor tag value if prediction is not used.
+- Raise KeyError if ZarrStore is missing requested chunk.
+
+2023.3.21
+
+- Fix reading MMstack with missing data (#187).
+
2023.3.15
-- Pass 4980 tests.
- Fix corruption using tile generators with prediction/compression (#185).
- Add parser for Micro-Manager MMStack series (breaking).
- Return micromanager_metadata IndexMap as numpy array (breaking).
@@ -793,7 +806,7 @@
from __future__ import annotations
-__version__ = '2023.3.15'
+__version__ = '2023.4.12'
__all__ = [
'TiffFile',
@@ -1827,7 +1840,9 @@
4. writeonce (bool): If *True*, write tag to first page
of a series only.
- Duplicate and select tags in TIFF.TAG_FILTERED are not written.
+ Duplicate and select tags in TIFF.TAG_FILTERED are not written
+ if the extratag is specified by integer code.
+ Extratags cannot be used to write IFD type tags.
contiguous:
If *False* (default), write data to a new series.
@@ -2584,7 +2599,8 @@
self._metadata = {} if not metadata else metadata.copy()
if self._omexml is not None:
if len(self._omexml.images) == 0:
- description = '' # rewritten later at end of file
+ # rewritten later at end of file
+ description = '\x00\x00\x00\x00'
else:
description = None
elif self._imagej:
@@ -2624,7 +2640,12 @@
description += '\x00' * 16 # add buffer for in-place update
# elif metadata is None and self._truncate:
# raise ValueError('cannot truncate without writing metadata')
- else:
+ elif description is not None:
+ if not isinstance(description, bytes):
+ description = description.encode('ascii')
+ self._descriptiontag = TiffTag(
+ self, 0, 270, 2, len(description), description, 0
+ )
description = None
if description is None:
@@ -2633,6 +2654,9 @@
else:
description = description.encode('ascii')
addtag(tags, 270, 2, 0, description, True)
+ self._descriptiontag = TiffTag(
+ self, 0, 270, 2, len(description), description, 0
+ )
del description
if software is None:
@@ -2972,11 +2996,10 @@
extratag: TagTuple
tagset = {t[0] for t in tags}
tagset.update(TIFF.TAG_FILTERED)
- if 270 in tagset:
- # allow duplicate ImageDescription
- tagset.remove(270)
for extratag in extratags:
- if extratag[0] not in tagset:
+ if extratag[0] in tagset:
+ log_warning(f'{self!r} not writing extratag {extratag[0]}')
+ else:
addtag(tags, *extratag)
del tagset
del extratags
@@ -3143,11 +3166,17 @@
elif code == tagbytecounts:
databytecountsoffset = offset, pos
elif code == 270:
- assert self._descriptiontag is not None
- self._descriptiontag.offset = (
- ifdpos + tagoffset + tagindex * tagsize
- )
- self._descriptiontag.valueoffset = ifdpos + pos
+ if (
+ self._descriptiontag is not None
+ and self._descriptiontag.offset == 0
+ and value.startswith(
+ self._descriptiontag.value
+ )
+ ):
+ self._descriptiontag.offset = (
+ ifdpos + tagoffset + tagindex * tagsize
+ )
+ self._descriptiontag.valueoffset = ifdpos + pos
elif code == 330:
subifdsoffsets = offset, pos
elif code == tagoffsets:
@@ -3155,13 +3184,17 @@
elif code == tagbytecounts:
databytecountsoffset = offset, None
elif code == 270:
- assert self._descriptiontag is not None
- self._descriptiontag.offset = (
- ifdpos + tagoffset + tagindex * tagsize
- )
- self._descriptiontag.valueoffset = (
- self._descriptiontag.offset + offsetsize + 4
- )
+ if (
+ self._descriptiontag is not None
+ and self._descriptiontag.offset == 0
+ and self._descriptiontag.value in tag[1][-4:]
+ ):
+ self._descriptiontag.offset = (
+ ifdpos + tagoffset + tagindex * tagsize
+ )
+ self._descriptiontag.valueoffset = (
+ self._descriptiontag.offset + offsetsize + 4
+ )
elif code == 330:
subifdsoffsets = offset, None
ifdsize = ifd.tell()
@@ -3212,10 +3245,7 @@
elif tile:
# write tiles
- if storedshape.contig_samples == 1:
- tileshape = tile
- else:
- tileshape = tile + (storedshape.contig_samples,)
+ tileshape = tile + (storedshape.contig_samples,)
tilesize = product(tileshape) * datadtype.itemsize
if dataiter is None:
@@ -3709,11 +3739,10 @@
elif not isinstance(value, bytes):
raise ValueError('TIFF strings must be 7-bit ASCII')
- if len(value) == 0 or value[-1] != b'\x00':
+ if len(value) == 0 or value[-1:] != b'\x00':
value += b'\x00'
count = len(value)
if code == 270:
- self._descriptiontag = TiffTag(self, 0, 270, 2, count, None, 0)
rawcount = int(value.find(b'\x00\x00'))
if rawcount < 0:
rawcount = count
@@ -5068,53 +5097,74 @@
self.pages.set_keyframe(0)
self.pages._load()
- # Baseline
- index = 0
- page = self.pages[index]
- series.append(
- TiffPageSeries(
- [page],
- page.shape,
- page.dtype,
- page.axes,
- name='Baseline',
- kind='svs',
- )
- )
- # Thumbnail
- index += 1
- if index == len(self.pages):
+ # baseline
+ firstpage = self.pages.first
+ if len(self.pages) == 1:
self.is_uniform = False
- return series
- page = self.pages[index]
- series.append(
- TiffPageSeries(
- [page],
- page.shape,
- page.dtype,
- page.axes,
- name='Thumbnail',
- kind='svs',
- )
+ return [
+ TiffPageSeries(
+ [firstpage],
+ firstpage.shape,
+ firstpage.dtype,
+ firstpage.axes,
+ name='Baseline',
+ kind='svs',
+ )
+ ]
+
+ # thumbnail
+ page = self.pages[1]
+ thumnail = TiffPageSeries(
+ [page],
+ page.shape,
+ page.dtype,
+ page.axes,
+ name='Thumbnail',
+ kind='svs',
)
- # Resolutions
- # TODO: resolutions not by two
- index += 1
+
+ # resolutions and focal planes
+ levels = {firstpage.shape: [firstpage]}
+ index = 2
while index < len(self.pages):
page = cast(TiffPage, self.pages[index])
if not page.is_tiled or page.is_reduced:
break
- series[0].levels.append(
+ if page.shape in levels:
+ levels[page.shape].append(page)
+ else:
+ levels[page.shape] = [page]
+ index += 1
+
+ zsize = len(levels[firstpage.shape])
+ if not all(len(level) == zsize for level in levels.values()):
+ log_warning(f'{self!r} SVS series focal planes do not match')
+ zsize = 1
+ baseline = TiffPageSeries(
+ levels[firstpage.shape],
+ (zsize,) + firstpage.shape,
+ firstpage.dtype,
+ 'Z' + firstpage.axes,
+ name='Baseline',
+ kind='svs',
+ )
+ for shape, level in levels.items():
+ if shape == firstpage.shape:
+ continue
+ page = level[0]
+ baseline.levels.append(
TiffPageSeries(
- [page],
- page.shape,
+ level,
+ (zsize,) + page.shape,
page.dtype,
- page.axes,
+ 'Z' + page.axes,
name='Resolution',
kind='svs',
)
)
- index += 1
+ series.append(baseline)
+ series.append(thumnail)
+
# Label, Macro; subfiletype 1, 9
for _ in range(2):
if index == len(self.pages):
@@ -5661,20 +5711,31 @@
found_keyframe = False
ifds = []
for page in aseries.pages:
- if page is None or page.subifds is None:
+ if (
+ page is None
+ or page.subifds is None
+ or page.subifds[level] < 8
+ ):
ifds.append(None)
continue
page.parent.filehandle.seek(page.subifds[level])
if page.keyframe == page:
- ifd = keyframe = TiffPage(self, (page.index, level))
+ ifd = keyframe = TiffPage(
+ self, (page.index, level + 1)
+ )
found_keyframe = True
elif not found_keyframe:
raise RuntimeError('no keyframe found')
else:
ifd = TiffFrame(
- self, (page.index, level), keyframe=keyframe
+ self, (page.index, level + 1), keyframe=keyframe
)
ifds.append(ifd)
+ if all(ifd_or_none is None for ifd_or_none in ifds):
+ log_warning(
+ f'{self!r} OME series level {level + 1} is empty'
+ )
+ break
# fix shape
shape = list(aseries.get_shape(False))
axes = aseries.get_axes(False)
@@ -5837,9 +5898,14 @@
elif size > indexmap.shape[0]:
# other files missing: squeeze shape
old_shape = shape
- min_index = numpy.min(indexmap[:, :4], axis=0).tolist()
- max_index = numpy.max(indexmap[:, :4], axis=0).tolist()
- shape = tuple(j - i + 1 for i, j in zip(min_index, max_index))
+ min_index = numpy.min(indexmap[:, :4], axis=0)
+ max_index = numpy.max(indexmap[:, :4], axis=0)
+ indexmap = indexmap.copy()
+ indexmap[:, :4] -= min_index
+ shape = tuple(
+ j - i + 1
+ for i, j in zip(min_index.tolist(), max_index.tolist())
+ )
shape = tuple(shape[i] for i in indexmap_order)
size = product(shape)
pages = [None] * size
@@ -8131,11 +8197,17 @@
else:
unpredict = TIFF.UNPREDICTORS[self.predictor]
except KeyError as exc:
+ if self.compression not in TIFF.IMAGE_COMPRESSIONS:
- def decode_raise_predictor(*args, exc=str(exc)[1:-1], **kwargs):
- raise ValueError(f'{exc}')
+ def decode_raise_predictor(
+ *args, exc=str(exc)[1:-1], **kwargs
+ ):
+ raise ValueError(f'{exc}')
+
+ return cache(decode_raise_predictor)
- return cache(decode_raise_predictor)
+ log_warning(f'{self!r} ignoring predictor {self.predictor}')
+ unpredict = None
if self.tags.get(339) is not None:
tag = self.tags[339] # SampleFormat
@@ -10892,7 +10964,7 @@
) from exc
elif not isinstance(value, bytes):
raise ValueError('TIFF strings must be 7-bit ASCII')
- if len(value) == 0 or value[-1] != b'\x00':
+ if len(value) == 0 or value[-1:] != b'\x00':
value += b'\x00'
count = len(value)
value = (value,)
@@ -12020,7 +12092,14 @@
return len(self._store)
def __contains__(self, key: object, /) -> bool:
- return key in self._store
+ if key in self._store:
+ return True
+ assert isinstance(key, str)
+ return self._contains(key)
+
+ def _contains(self, key: str, /) -> bool:
+ """Return if key is in store."""
+ raise NotImplementedError
def __delitem__(self, key: object, /) -> None:
raise PermissionError('ZarrStore is read-only')
@@ -12656,23 +12735,26 @@
if not hasattr(jsonfile, 'write'):
fh.close()
+ def _contains(self, key: str, /) -> bool:
+ """Return if key is in store."""
+ try:
+ _, page, _, offset, bytecount = self._parse_key(key)
+ except KeyError:
+ return False
+ return (
+ page is not None
+ and offset is not None
+ and bytecount is not None
+ and offset > 0
+ and bytecount > 0
+ )
+
def _getitem(self, key: str, /) -> NDArray[Any]:
"""Return chunk from file."""
keyframe, page, chunkindex, offset, bytecount = self._parse_key(key)
- if self._chunkmode:
- chunks = keyframe.shape
- else:
- chunks = keyframe.chunks
-
if page is None or offset == 0 or bytecount == 0:
- assert keyframe.dtype is not None
- chunk = ZarrStore._empty_chunk(
- chunks, keyframe.dtype, self._fillvalue
- )
- if self._transform is not None:
- chunk = self._transform(chunk)
- return chunk
+ raise KeyError(key)
fh = page.parent.filehandle
@@ -12703,6 +12785,10 @@
if self._transform is not None:
chunk = self._transform(chunk)
+ if self._chunkmode:
+ chunks = keyframe.shape
+ else:
+ chunks = keyframe.chunks
if chunk.size != product(chunks):
raise RuntimeError(f'{chunk.size} != {product(chunks)}')
return chunk # .tobytes()
@@ -12990,17 +13076,21 @@
}
)
+ def _contains(self, key: str, /) -> bool:
+ """Return if key is in store."""
+ try:
+ indices = tuple(int(i) for i in key.split('.'))
+ except Exception:
+ return False
+ return indices in self._lookup
+
def _getitem(self, key: str, /) -> NDArray[Any]:
"""Return chunk from file."""
indices = tuple(int(i) for i in key.split('.'))
filename = self._lookup.get(indices, None)
if filename is None:
- chunk = ZarrStore._empty_chunk(
- self._chunks, self._dtype, self._fillvalue
- )
- else:
- chunk = self._imread(filename, **self._kwargs)
- return chunk
+ raise KeyError(key)
+ return self._imread(filename, **self._kwargs)
def _setitem(self, key: str, value: bytes, /) -> None:
raise PermissionError('ZarrStore is read-only')
@@ -17182,8 +17272,12 @@
330, # SubIFDs,
338, # ExtraSamples
339, # SampleFormat
+ 400, # GlobalParametersIFD
32997, # ImageDepth
32998, # TileDepth
+ 34665, # ExifTag
+ 34853, # GPSTag
+ 40965, # InteroperabilityTag
)
)