tifffile

Форк
0
/
test_tifffile.py 
20892 строки · 750.5 Кб
1
# test_tifffile.py
2

3
# Copyright (c) 2008-2024, Christoph Gohlke
4
# All rights reserved.
5
#
6
# Redistribution and use in source and binary forms, with or without
7
# modification, are permitted provided that the following conditions are met:
8
#
9
# 1. Redistributions of source code must retain the above copyright notice,
10
#    this list of conditions and the following disclaimer.
11
#
12
# 2. Redistributions in binary form must reproduce the above copyright notice,
13
#    this list of conditions and the following disclaimer in the documentation
14
#    and/or other materials provided with the distribution.
15
#
16
# 3. Neither the name of the copyright holder nor the names of its
17
#    contributors may be used to endorse or promote products derived from
18
#    this software without specific prior written permission.
19
#
20
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
# POSSIBILITY OF SUCH DAMAGE.
31

32
# mypy: allow-untyped-defs
33
# mypy: check-untyped-defs=False
34

35
"""Unittests for the tifffile package.
36

37
Public data files can be requested from the author.
38
Private data files are not available due to size and copyright restrictions.
39

40
:Version: 2024.8.30
41

42
"""
43

44
import binascii
45
import datetime
46
import glob
47
import json
48
import logging
49
import math
50
import mmap
51
import os
52
import pathlib
53
import random
54
import re
55
import struct
56
import sys
57
import tempfile
58
import urllib.error
59
import urllib.request
60
from io import BytesIO
61

62
import numpy
63
import pytest
64
import tifffile
65
from numpy.testing import (
66
    assert_allclose,
67
    assert_array_almost_equal,
68
    assert_array_equal,
69
    assert_raises,
70
)
71

72
try:
73
    from tifffile import *  # noqa: F403
74

75
    STAR_IMPORTED = (
76
        TIFF,  # noqa: F405
77
        imwrite,  # noqa
78
        imread,  # noqa
79
        imshow,  # noqa
80
        TiffWriter,  # noqa
81
        TiffReader,  # noqa
82
        TiffFile,  # noqa
83
        TiffFileError,  # noqa
84
        TiffSequence,  # noqa
85
        TiffPage,  # noqa
86
        TiffFrame,  # noqa
87
        FileHandle,  # noqa
88
        FileSequence,  # noqa
89
        Timer,  # noqa
90
        lazyattr,  # noqa
91
        logger,  # noqa
92
        strptime,  # noqa
93
        natural_sorted,  # noqa
94
        stripnull,  # noqa
95
        memmap,  # noqa
96
        repeat_nd,  # noqa
97
        format_size,  # noqa
98
        product,  # noqa
99
        create_output,  # noqa
100
        askopenfilename,  # noqa
101
        read_scanimage_metadata,  # noqa
102
        read_micromanager_metadata,  # noqa
103
        OmeXmlError,  # noqa
104
        OmeXml,  # noqa
105
    )  # type: tuple[object, ...]
106
except NameError:
107
    STAR_IMPORTED = ()
108

109
from tifffile import (  # noqa: F401
110
    CHUNKMODE,
111
    COMPRESSION,
112
    DATATYPE,
113
    EXTRASAMPLE,
114
    FILETYPE,
115
    FILLORDER,
116
    OFILETYPE,
117
    ORIENTATION,
118
    PHOTOMETRIC,
119
    PLANARCONFIG,
120
    PREDICTOR,
121
    RESUNIT,
122
    SAMPLEFORMAT,
123
    TIFF,
124
    FileCache,
125
    FileHandle,
126
    FileSequence,
127
    OmeXml,
128
    OmeXmlError,
129
    TiffFile,
130
    TiffFileError,
131
    TiffFrame,
132
    TiffPage,
133
    TiffPageSeries,
134
    TiffReader,
135
    TiffSequence,
136
    TiffTag,
137
    TiffTags,
138
    TiffWriter,
139
    Timer,
140
    ZarrFileSequenceStore,
141
    ZarrStore,
142
    ZarrTiffStore,
143
)
144
from tifffile.tifffile import _squeeze_axes as squeeze_axes
145
from tifffile.tifffile import (  # noqa: F401
146
    apply_colormap,
147
    asbool,
148
    askopenfilename,
149
    astrotiff_description_metadata,
150
    byteorder_compare,
151
    byteorder_isnative,
152
    bytes2str,
153
    check_shape,
154
    create_output,
155
    enumarg,
156
    epics_datetime,
157
    excel_datetime,
158
    fluoview_description_metadata,
159
    format_size,
160
    hexdump,
161
    imagej_description,
162
    imagej_description_metadata,
163
    imagej_shape,
164
    imread,
165
    imshow,
166
    imwrite,
167
    julian_datetime,
168
    lazyattr,
169
    logger,
170
    lsm2bin,
171
    matlabstr2py,
172
    memmap,
173
    metaseries_description_metadata,
174
    natural_sorted,
175
    order_axes,
176
    parse_filenames,
177
    pformat,
178
    pilatus_description_metadata,
179
    product,
180
    read_micromanager_metadata,
181
    read_scanimage_metadata,
182
    reorient,
183
    repeat_nd,
184
    reshape_axes,
185
    reshape_nd,
186
    scanimage_artist_metadata,
187
    scanimage_description_metadata,
188
    sequence,
189
    shaped_description,
190
    shaped_description_metadata,
191
    snipstr,
192
    stk_description_metadata,
193
    stripascii,
194
    stripnull,
195
    strptime,
196
    subresolution,
197
    svs_description_metadata,
198
    tiff2fsspec,
199
    tiffcomment,
200
    transpose_axes,
201
    unpack_rgb,
202
    validate_jhove,
203
    xml2dict,
204
)
205

206
HERE = os.path.dirname(__file__)
207
TEMP_DIR = os.path.join(HERE, '_tmp')
208
PRIVATE_DIR = os.path.join(HERE, 'data', 'private')
209
PUBLIC_DIR = os.path.join(HERE, 'data', 'public')
210

211
IS_BE = sys.byteorder == 'big'
212
IS_PYPY = 'pypy' in sys.version.lower()
213
IS_WIN = sys.platform == 'win32'
214
IS_CG = os.environ.get('COMPUTERNAME', '').startswith('CG-K')
215

216

217
# skip certain tests
218
def skip(key, default):
219
    return os.getenv(key, default) in {True, 1, '1'}
220

221

222
# skip tests requiring large memory
223
SKIP_LARGE = skip('SKIP_LARGE', sys.maxsize < 2**32)
224
SKIP_EXTENDED = skip('SKIP_EXTENDED', False)
225
# skip public files
226
SKIP_PUBLIC = skip('SKIP_PUBLIC', not os.path.exists(PUBLIC_DIR))
227
# skip private files
228
SKIP_PRIVATE = skip('SKIP_PRIVATE', not os.path.exists(PRIVATE_DIR))
229
# skip validate written files with jhove
230
SKIP_VALIDATE = skip('SKIP_VALIDATE', True)
231
SKIP_CODECS = skip('SKIP_CODECS', False)
232
SKIP_ZARR = skip('SKIP_ZARR', False)
233
SKIP_DASK = skip('SKIP_DASK', False)
234
SKIP_NDTIFF = skip('SKIP_NDTIFF', False)
235
SKIP_HTTP = skip('SKIP_HTTP', not IS_CG)
236
REASON = 'skipped'
237

238
FILE_FLAGS = ['is_' + a for a in TIFF.FILE_FLAGS]
239
FILE_FLAGS += [name for name in dir(TiffFile) if name.startswith('is_')]
240
PAGE_FLAGS = [name for name in dir(TiffPage) if name.startswith('is_')]
241

242
URL = 'http://localhost:8386/'  # TEMP_DIR
243

244
if not SKIP_HTTP:
245
    try:
246
        urllib.request.urlopen(URL + '/test/test.txt', timeout=0.5)
247
    except (urllib.error.URLError, TimeoutError):
248
        SKIP_HTTP = True
249

250
if not os.path.exists(TEMP_DIR):
251
    TEMP_DIR = tempfile.gettempdir()
252

253
if not SKIP_CODECS:
254
    try:
255
        import imagecodecs
256

257
        SKIP_CODECS = False
258
    except ImportError:
259
        SKIP_CODECS = True
260

261
if IS_PYPY:
262
    SKIP_ZARR = True
263
    SKIP_DASK = True
264
    SKIP_HTTP = True
265

266
if SKIP_ZARR:
267
    zarr = None
268
else:
269
    try:
270
        import fsspec  # type: ignore
271
        import zarr  # type: ignore
272
    except ImportError:
273
        zarr = None
274
        fsspec = None  # type: ignore
275
        SKIP_ZARR = True
276

277
if SKIP_DASK:
278
    dask = None
279
else:
280
    try:
281
        import dask  # type: ignore
282
        import dask.array  # type: ignore
283
    except ImportError:
284
        dask = None
285
        SKIP_DASK = True
286

287
if SKIP_NDTIFF:
288
    ndtiff = None
289
else:
290
    try:
291
        import ndtiff  # type: ignore
292
    except ImportError:
293
        ndtiff = None
294
        SKIP_NDTIFF = True
295

296

297
def config() -> str:
298
    """Return test configuration."""
299
    this = sys.modules[__name__]
300
    return ' | '.join(
301
        a for a in dir(this) if a.startswith('SKIP_') and getattr(this, a)
302
    )
303

304

305
def data_file(pathname, base, expand=True):
306
    """Return path to test file(s)."""
307
    path = os.path.join(base, *pathname.split('/'))
308
    if expand and any(i in path for i in '*?'):
309
        return glob.glob(path)
310
    return path
311

312

313
def private_file(pathname, base=PRIVATE_DIR, expand=True):
314
    """Return path to private test file(s)."""
315
    return data_file(pathname, base, expand=expand)
316

317

318
def public_file(pathname, base=PUBLIC_DIR, expand=True):
319
    """Return path to public test file(s)."""
320
    return data_file(pathname, base, expand=expand)
321

322

323
def random_data(dtype, shape):
324
    """Return random numpy array."""
325
    # TODO: use nd noise
326
    if dtype == '?':
327
        return numpy.random.rand(*shape) < 0.5
328
    data = numpy.random.rand(*shape) * 255
329
    data = data.astype(dtype)
330
    return data
331

332

333
def assert_file_flags(tiff_file):
334
    """Access all flags of TiffFile."""
335
    for flag in FILE_FLAGS:
336
        getattr(tiff_file, flag)
337

338

339
def assert_page_flags(tiff_page):
340
    """Access all flags of TiffPage."""
341
    for flag in PAGE_FLAGS:
342
        getattr(tiff_page, flag)
343

344

345
def assert__str__(tif, detail=3):
346
    """Call TiffFile._str and __repr__ functions."""
347
    for i in range(detail + 1):
348
        tif._str(detail=i)
349
    repr(tif)
350
    str(tif)
351
    repr(tif.pages)
352
    str(tif.pages)
353
    if len(tif.pages) > 0:
354
        page = tif.pages.first
355
        repr(page)
356
        str(page)
357
        str(page.tags)
358
        page.flags
359
        page.name
360
        page.dims
361
        page.sizes
362
        page.coords
363
    repr(tif.series)
364
    str(tif.series)
365
    if len(tif.series) > 0:
366
        series = tif.series[0]
367
        repr(series)
368
        str(series)
369

370

371
def assert__repr__(obj):
372
    """Call object's __repr__ and __str__ function."""
373
    repr(obj)
374
    str(obj)
375

376

377
def assert_valid_omexml(omexml):
378
    """Validate OME-XML schema."""
379
    if not SKIP_HTTP:
380
        OmeXml.validate(omexml, assert_=True)
381

382

383
def assert_valid_tiff(filename, *args, **kwargs):
384
    """Validate TIFF file using jhove script."""
385
    if SKIP_VALIDATE:
386
        return
387
    validate_jhove(filename, 'jhove.cmd', *args, **kwargs)
388

389

390
def assert_decode_method(page, image=None):
391
    """Call TiffPage.decode on all segments and compare to TiffPage.asarray."""
392
    fh = page.parent.filehandle
393
    if page.is_tiled:
394
        offsets = page.tags['TileOffsets'].value
395
        bytecounts = page.tags['TileByteCounts'].value
396
    else:
397
        offsets = page.tags['StripOffsets'].value
398
        bytecounts = page.tags['StripByteCounts'].value
399
    if image is None:
400
        image = page.asarray()
401
    for i, (o, b) in enumerate(zip(offsets, bytecounts)):
402
        fh.seek(o)
403
        strile = fh.read(b)
404
        strile, index, shape = page.decode(strile, i)
405
        assert image.reshape(page.shaped)[index] == strile[0, 0, 0, 0]
406

407

408
def assert_aszarr_method(obj, image=None, chunkmode=None, **kwargs):
409
    """Assert aszarr returns same data as asarray."""
410
    if SKIP_ZARR or zarr is None:
411
        return
412
    if image is None:
413
        image = obj.asarray(**kwargs)
414
    with obj.aszarr(chunkmode=chunkmode, **kwargs) as store:
415
        data = zarr.open(store, mode='r')
416
        if isinstance(data, zarr.Group):
417
            data = data[0]
418
        assert_array_equal(data, image)
419
        del data
420

421

422
class TempFileName:
423
    """Temporary file name context manager."""
424

425
    name: str
426
    remove: bool
427

428
    def __init__(self, name=None, ext='.tif', remove=False):
429
        self.remove = remove or TEMP_DIR == tempfile.gettempdir()
430
        if not name:
431
            fh = tempfile.NamedTemporaryFile(prefix='test_')
432
            self.name = fh.named
433
            fh.close()
434
        else:
435
            self.name = os.path.join(TEMP_DIR, f'test_{name}{ext}')
436

437
    def __enter__(self) -> str:
438
        return self.name
439

440
    def __exit__(self, exc_type, exc_value, traceback):
441
        if self.remove:
442
            try:
443
                os.remove(self.name)
444
            except Exception:
445
                pass
446

447

448
numpy.set_printoptions(suppress=True, precision=5)
449

450

451
###############################################################################
452

453
# Tests for specific issues
454

455

456
def test_issue_star_import():
457
    """Test from tifffile import *."""
458
    assert len(STAR_IMPORTED) > 0
459
    assert lsm2bin not in STAR_IMPORTED
460

461

462
@pytest.mark.skipif(__doc__ is None, reason='__doc__ is None')
463
def test_issue_version_mismatch():
464
    """Test 'tifffile.__version__' matches docstrings."""
465
    ver = ':Version: ' + tifffile.__version__
466
    assert ver in __doc__
467
    assert ver in tifffile.__doc__
468

469

470
def test_issue_deprecated_import():
471
    """Test deprecated functions can still be imported."""
472
    from tifffile import imsave
473

474
    with TempFileName('issue_deprecated_import') as fname:
475
        with pytest.warns(DeprecationWarning):
476
            imsave(fname, [[0]])
477
        imread(fname)
478
        with TiffWriter(fname) as tif:
479
            with pytest.warns(DeprecationWarning):
480
                tif.save([[0]])
481
        imread(fname)
482

483
    # from tifffile import decodelzw
484
    # from tifffile import decode_lzw
485

486

487
def test_issue_imread_kwargs():
488
    """Test that is_flags are handled by imread."""
489
    data = random_data(numpy.uint16, (5, 63, 95))
490
    with TempFileName('issue_imread_kwargs') as fname:
491
        with TiffWriter(fname) as tif:
492
            for image in data:
493
                tif.write(image)  # create 5 series
494
        assert_valid_tiff(fname)
495
        image = imread(fname, pattern=None)  # reads first series
496
        assert_array_equal(image, data[0])
497
        image = imread(fname, is_shaped=False)  # reads all pages
498
        assert_array_equal(image, data)
499

500

501
def test_issue_imread_kwargs_legacy():
502
    """Test legacy arguments no longer work as of 2022.4.22
503

504
    Specifying 'fastij', 'movie', 'multifile', 'multifile_close', or
505
    'pages' raises TypeError.
506
    Specifying 'key' and 'pages' raises TypeError.
507
    Specifying 'pages' in TiffFile constructor raises TypeError.
508

509
    """
510
    data = random_data(numpy.uint8, (3, 21, 31))
511
    with TempFileName('issue_imread_kwargs_legacy') as fname:
512
        imwrite(fname, data, photometric=PHOTOMETRIC.MINISBLACK)
513
        with pytest.raises(TypeError):
514
            imread(fname, fastij=True)
515
        with pytest.raises(TypeError):
516
            imread(fname, movie=True)
517
        with pytest.raises(TypeError):
518
            imread(fname, multifile=True)
519
        with pytest.raises(TypeError):
520
            imread(fname, multifile_close=True)
521

522
        with pytest.raises(TypeError):
523
            TiffFile(fname, fastij=True)
524
        with pytest.raises(TypeError):
525
            TiffFile(fname, multifile=True)
526
        with pytest.raises(TypeError):
527
            TiffFile(fname, multifile_close=True)
528
        with pytest.raises(TypeError):
529
            imread(fname, key=0, pages=[1, 2])
530
        with pytest.raises(TypeError):
531
            TiffFile(fname, pages=[1, 2])
532

533

534
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
535
def test_issue_infinite_loop():
536
    """Test infinite loop reading more than two tags of same code in IFD."""
537
    # Reported by D. Hughes on 2019.7.26
538
    # the test file is corrupted but should not cause infinite loop
539
    fname = private_file('gdk-pixbuf/bug784903-overflow-dimensions.tiff')
540
    with TiffFile(fname) as tif:
541
        page = tif.pages.first
542
        assert page.compression == 0  # invalid
543
        assert__str__(tif)
544

545

546
@pytest.mark.skipif(
547
    SKIP_PRIVATE or SKIP_CODECS or not imagecodecs.JPEG.available,
548
    reason=REASON,
549
)
550
def test_issue_jpeg_ia():
551
    """Test JPEG compressed intensity image with alpha channel."""
552
    # no extrasamples!
553
    fname = private_file('issues/jpeg_ia.tiff')
554
    with TiffFile(fname) as tif:
555
        page = tif.pages.first
556
        assert page.compression == COMPRESSION.JPEG
557
        assert_array_equal(
558
            page.asarray(),
559
            numpy.array([[[0, 0], [255, 255]]], dtype=numpy.uint8),
560
        )
561
        assert__str__(tif)
562

563

564
@pytest.mark.skipif(
565
    SKIP_PRIVATE or SKIP_CODECS or not imagecodecs.JPEG.available,
566
    reason=REASON,
567
)
568
def test_issue_jpeg_palette():
569
    """Test invalid JPEG compressed intensity image with palette."""
570
    # https://forum.image.sc/t/viv-and-avivator/45999/24
571
    fname = private_file('issues/FL_cells.ome.tif')
572
    with TiffFile(fname) as tif:
573
        page = tif.pages.first
574
        assert page.compression == COMPRESSION.JPEG
575
        assert page.colormap is not None
576
        data = tif.asarray()
577
        assert data.shape == (4, 1024, 1024)
578
        assert data.dtype == numpy.uint8
579
        assert data[2, 512, 512] == 10
580
        assert_aszarr_method(tif, data)
581
        assert__str__(tif)
582

583

584
def test_issue_specific_pages():
585
    """Test read second page."""
586
    data = random_data(numpy.uint8, (3, 21, 31))
587
    with TempFileName('issue_specific_pages') as fname:
588
        imwrite(fname, data, photometric=PHOTOMETRIC.MINISBLACK)
589
        image = imread(fname)
590
        assert image.shape == (3, 21, 31)
591
        # UserWarning: can not reshape (21, 31) to (3, 21, 31)
592
        image = imread(fname, key=1)
593
        assert image.shape == (21, 31)
594
        assert_array_equal(image, data[1])
595
    with TempFileName('issue_specific_pages_bigtiff') as fname:
596
        imwrite(fname, data, bigtiff=True, photometric=PHOTOMETRIC.MINISBLACK)
597
        image = imread(fname)
598
        assert image.shape == (3, 21, 31)
599
        # UserWarning: can not reshape (21, 31) to (3, 21, 31)
600
        image = imread(fname, key=1)
601
        assert image.shape == (21, 31)
602
        assert_array_equal(image, data[1])
603

604

605
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
606
def test_issue_circular_ifd(caplog):
607
    """Test circular IFD logs error but is still readable."""
608
    fname = public_file('Tiff-Library-4J/IFD struct/Circular E.tif')
609
    with TiffFile(fname) as tif:
610
        assert len(tif.pages) == 2
611
        assert 'invalid circular reference' in caplog.text
612
        image = tif.asarray()
613
        assert image.shape == (2, 1500, 2000, 3)
614
        assert image[1, 1499, 1999, 2] == 110
615

616

617
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
618
def test_issue_bad_description(caplog):
619
    """Test page.description is empty when ImageDescription is not ASCII."""
620
    # ImageDescription is not ASCII but bytes
621
    fname = private_file('stk/cells in the eye2.stk')
622
    with TiffFile(fname) as tif:
623
        page = tif.pages.first
624
        assert page.description == ''
625
        assert__str__(tif)
626
    assert 'coercing invalid ASCII to bytes' in caplog.text
627

628

629
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
630
def test_issue_bad_ascii(caplog):
631
    """Test coerce invalid ASCII to bytes."""
632
    # ImageID is not ASCII but bytes
633
    # https://github.com/blink1073/tifffile/pull/38
634
    fname = private_file('issues/tifffile_013_tagfail.tif')
635
    with TiffFile(fname) as tif:
636
        tags = tif.pages.first.tags
637
        assert tags['ImageID'].value[-8:] == b'rev 2893'
638
        assert__str__(tif)
639
    assert 'coercing invalid ASCII to bytes' in caplog.text
640

641

642
def test_issue_sampleformat():
643
    """Test write correct number of SampleFormat values."""
644
    # https://github.com/ngageoint/geopackage-tiff-java/issues/5
645
    data = random_data(numpy.int16, (256, 256, 4))
646
    with TempFileName('issue_sampleformat') as fname:
647
        imwrite(fname, data, photometric=PHOTOMETRIC.RGB)
648
        with TiffFile(fname) as tif:
649
            tags = tif.pages.first.tags
650
            assert tags['SampleFormat'].value == (2, 2, 2, 2)
651
            assert tags['ExtraSamples'].value == (2,)
652
            assert__str__(tif)
653

654

655
def test_issue_sampleformat_default():
656
    """Test SampleFormat are not written for UINT."""
657
    data = random_data(numpy.uint8, (256, 256, 4))
658
    with TempFileName('issue_sampleformat_default') as fname:
659
        imwrite(fname, data, photometric=PHOTOMETRIC.RGB)
660
        with TiffFile(fname) as tif:
661
            tags = tif.pages.first.tags
662
            'SampleFormat' not in tags
663
            assert tags['ExtraSamples'].value == (2,)
664
            assert__str__(tif)
665

666

667
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
668
def test_issue_palette_with_extrasamples():
669
    """Test read palette with extra samples."""
670
    # https://github.com/python-pillow/Pillow/issues/1597
671
    fname = private_file('issues/palette_with_extrasamples.tif')
672
    with TiffFile(fname) as tif:
673
        assert len(tif.pages) == 1
674
        page = tif.pages.first
675
        assert page.photometric == PHOTOMETRIC.PALETTE
676
        assert page.compression == COMPRESSION.LZW
677
        assert page.imagewidth == 518
678
        assert page.imagelength == 556
679
        assert page.bitspersample == 8
680
        assert page.samplesperpixel == 2
681
        # assert data
682
        image = page.asrgb()
683
        assert image.shape == (556, 518, 3)
684
        assert image.dtype == numpy.uint16
685
        image = tif.asarray()
686
        # self.assertEqual(image.shape[-3:], (556, 518, 2))
687
        assert image.shape == (556, 518, 2)
688
        assert image.dtype == numpy.uint8
689
        assert_aszarr_method(tif, image)
690
        del image
691
        assert__str__(tif)
692

693

694
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
695
def test_issue_incorrect_rowsperstrip_count():
696
    """Test read incorrect count for rowsperstrip; bitspersample = 4."""
697
    # https://github.com/python-pillow/Pillow/issues/1544
698
    fname = private_file('bad/incorrect_count.tiff')
699
    with TiffFile(fname) as tif:
700
        assert len(tif.pages) == 1
701
        page = tif.pages.first
702
        assert page.photometric == PHOTOMETRIC.PALETTE
703
        assert page.compression == COMPRESSION.ADOBE_DEFLATE
704
        assert page.imagewidth == 32
705
        assert page.imagelength == 32
706
        assert page.bitspersample == 4
707
        assert page.samplesperpixel == 1
708
        assert page.rowsperstrip == 32
709
        assert page.dataoffsets[0] == 8
710
        assert page.databytecounts[0] == 89
711
        # assert data
712
        image = page.asrgb()
713
        assert image.shape == (32, 32, 3)
714
        assert_aszarr_method(page)
715
        del image
716
        assert__str__(tif)
717

718

719
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
720
def test_issue_extra_strips(caplog):
721
    """Test read extra strips."""
722
    # https://github.com/opencv/opencv/issues/17054
723
    fname = private_file('issues/extra_strips.tif')
724
    with TiffFile(fname) as tif:
725
        assert not tif.is_bigtiff
726
        assert len(tif.pages) == 1
727
        page = tif.pages.first
728
        assert page.tags['StripOffsets'].value == (8, 0, 0)
729
        assert page.tags['StripByteCounts'].value == (55064448, 0, 0)
730
        assert page.dataoffsets[0] == 8
731
        assert page.databytecounts[0] == 55064448
732
        assert page.is_contiguous
733
        # assert data
734
        image = tif.asarray()
735
        assert image.shape == (2712, 3384, 3)
736
        assert_aszarr_method(page, image)
737
    assert 'incorrect StripOffsets count' in caplog.text
738
    assert 'incorrect StripByteCounts count' in caplog.text
739

740

741
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
742
def test_issue_no_bytecounts(caplog):
743
    """Test read no bytecounts."""
744
    fname = private_file('bad/img2_corrupt.tif')
745
    with TiffFile(fname) as tif:
746
        assert not tif.is_bigtiff
747
        assert len(tif.pages) == 1
748
        page = tif.pages.first
749
        assert page.is_contiguous
750
        assert page.planarconfig == PLANARCONFIG.CONTIG
751
        assert page.dataoffsets[0] == 512
752
        assert page.databytecounts[0] == 0
753
        # assert data
754
        image = tif.asarray()
755
        assert image.shape == (800, 1200)
756
        # fails: assert_aszarr_method(tif, image)
757
    assert 'invalid value offset 0' in caplog.text
758
    assert 'invalid data type 31073' in caplog.text
759
    assert 'invalid page offset 808333686' in caplog.text
760

761

762
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
763
def test_issue_missing_eoi_in_strips():
764
    """Test read LZW strips without EOI."""
765
    # 256x256 uint16, lzw, imagej
766
    # Strips do not contain an EOI code as required by the TIFF spec.
767
    # File generated by `tiffcp -c lzw Z*.tif stack.tif` from
768
    # Bars-G10-P15.zip
769
    # Failed with "series 0 failed: string size must be a multiple of
770
    # element size"
771
    # Reported by Kai Wohlfahrt on 3/7/2014
772
    fname = private_file('issues/stack.tif')
773
    with TiffFile(fname) as tif:
774
        assert tif.is_imagej
775
        assert tif.byteorder == '<'
776
        assert len(tif.pages) == 128
777
        assert len(tif.series) == 1
778
        # assert page properties
779
        page = tif.pages.first
780
        assert page.imagewidth == 256
781
        assert page.imagelength == 256
782
        assert page.bitspersample == 16
783
        # assert series properties
784
        series = tif.series[0]
785
        assert series.shape == (128, 256, 256)
786
        assert series.dtype == numpy.uint16
787
        assert series.axes == 'IYX'
788
        # assert ImageJ tags
789
        ijmeta = tif.imagej_metadata
790
        assert ijmeta is not None
791
        assert ijmeta['ImageJ'] == '1.41e'
792
        # assert data
793
        data = tif.asarray()
794
        assert data.shape == (128, 256, 256)
795
        assert data.dtype == numpy.uint16
796
        assert data[64, 128, 128] == 19226
797
        assert_aszarr_method(tif, data)
798
        del data
799
        assert__str__(tif)
800

801

802
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
803
def test_issue_imagej_grascalemode():
804
    """Test read ImageJ grayscale mode RGB image."""
805
    # https://github.com/cgohlke/tifffile/issues/6
806
    fname = private_file('issues/hela-cells.tif')
807
    with TiffFile(fname) as tif:
808
        assert tif.is_imagej
809
        assert tif.byteorder == '>'
810
        assert len(tif.pages) == 1
811
        assert len(tif.series) == 1
812
        # assert page properties
813
        page = tif.pages.first
814
        assert page.photometric == PHOTOMETRIC.RGB
815
        assert page.imagewidth == 672
816
        assert page.imagelength == 512
817
        assert page.bitspersample == 16
818
        assert page.is_contiguous
819
        # assert series properties
820
        series = tif.series[0]
821
        assert series.shape == (512, 672, 3)
822
        assert series.dtype == numpy.uint16
823
        assert series.axes == 'YXS'
824
        # assert ImageJ tags
825
        ijmeta = tif.imagej_metadata
826
        assert ijmeta is not None
827
        assert ijmeta['ImageJ'] == '1.52p'
828
        assert ijmeta['channels'] == 3
829
        # assert data
830
        data = tif.asarray()
831
        assert isinstance(data, numpy.ndarray)
832
        assert data.shape == (512, 672, 3)
833
        assert data.dtype == numpy.uint16
834
        assert tuple(data[255, 336]) == (440, 378, 298)
835
        assert_aszarr_method(tif, data)
836
        assert__str__(tif)
837

838

839
@pytest.mark.parametrize('byteorder', ['>', '<'])
840
def test_issue_valueoffset(byteorder):
841
    """Test read TiffTag.valueoffsets."""
842
    unpack = struct.unpack
843
    data = random_data(byteorder + 'u2', (2, 19, 31))
844
    software = 'test_tifffile'
845
    bo = {'>': 'be', '<': 'le'}[byteorder]
846
    with TempFileName(f'issue_valueoffset_{bo}') as fname:
847
        imwrite(
848
            fname,
849
            data,
850
            software=software,
851
            photometric=PHOTOMETRIC.MINISBLACK,
852
            extratags=[(65535, 3, 2, (21, 22), True)],
853
        )
854
        with TiffFile(fname, _useframes=True) as tif:
855
            with open(fname, 'rb') as fh:
856
                page = tif.pages.first
857
                # inline value
858
                fh.seek(page.tags['ImageLength'].valueoffset)
859
                assert (
860
                    page.imagelength
861
                    == unpack(tif.byteorder + 'I', fh.read(4))[0]
862
                )
863
                # two inline values
864
                fh.seek(page.tags[65535].valueoffset)
865
                assert unpack(tif.byteorder + 'H', fh.read(2))[0] == 21
866
                # separate value
867
                fh.seek(page.tags['Software'].valueoffset)
868
                assert page.software == bytes2str(fh.read(13))
869
                # TiffFrame
870
                page = tif.pages[1].aspage()
871
                fh.seek(page.tags['StripOffsets'].valueoffset)
872
                assert (
873
                    page.dataoffsets[0]
874
                    == unpack(tif.byteorder + 'I', fh.read(4))[0]
875
                )
876
                tag = page.tags['ImageLength']
877
                assert tag.name == 'ImageLength'
878
                assert tag.dtype_name == 'LONG'
879
                assert tag.dataformat == '1I'
880
                assert tag.valuebytecount == 4
881

882

883
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
884
def test_issue_pages_number():
885
    """Test number of pages."""
886
    fname = public_file('tifffile/100000_pages.tif')
887
    with TiffFile(fname) as tif:
888
        assert len(tif.pages) == 100000
889
        assert__str__(tif, 0)
890

891

892
def test_issue_pages_iterator():
893
    """Test iterate over pages in series."""
894
    data = random_data(numpy.int8, (8, 219, 301))
895
    with TempFileName('issue_page_iterator') as fname:
896
        imwrite(fname, data[0])
897
        imwrite(
898
            fname,
899
            data,
900
            photometric=PHOTOMETRIC.MINISBLACK,
901
            append=True,
902
            metadata={'axes': 'ZYX'},
903
        )
904
        imwrite(fname, data[-1], append=True)
905
        with TiffFile(fname) as tif:
906
            assert len(tif.pages) == 10
907
            assert len(tif.series) == 3
908
            page = tif.pages[1]
909
            assert isinstance(page, TiffPage)
910
            assert page.is_contiguous
911
            assert page.photometric == PHOTOMETRIC.MINISBLACK
912
            assert page.imagewidth == 301
913
            assert page.imagelength == 219
914
            assert page.samplesperpixel == 1
915
            # test read series 1
916
            series = tif.series[1]
917
            assert len(series._pages) == 1
918
            assert len(series.pages) == 8
919
            image = series.asarray()
920
            assert_array_equal(data, image)
921
            for i, page in enumerate(series.pages):
922
                assert page is not None
923
                im = page.asarray()
924
                assert_array_equal(image[i], im)
925
            assert__str__(tif)
926

927

928
def test_issue_tile_partial():
929
    """Test write single tiles larger than image data."""
930
    # https://github.com/cgohlke/tifffile/issues/3
931
    data = random_data(numpy.uint8, (3, 15, 15, 15))
932
    with TempFileName('issue_tile_partial_2d') as fname:
933
        imwrite(fname, data[0, 0], tile=(16, 16))
934
        with TiffFile(fname) as tif:
935
            assert len(tif.pages) == 1
936
            page = tif.pages.first
937
            assert not page.is_contiguous
938
            assert page.is_tiled
939
            assert (
940
                page.tags['TileOffsets'].value[0]
941
                + page.tags['TileByteCounts'].value[0]
942
                == tif.filehandle.size
943
            )
944
            assert_array_equal(page.asarray(), data[0, 0])
945
            assert_aszarr_method(page, data[0, 0])
946
            assert__str__(tif)
947

948
    with TempFileName('issue_tile_partial_3d') as fname:
949
        imwrite(fname, data[0], tile=(16, 16, 16))
950
        with TiffFile(fname) as tif:
951
            assert len(tif.pages) == 1
952
            page = tif.pages.first
953
            assert not page.is_contiguous
954
            assert page.is_tiled
955
            assert page.is_volumetric
956
            assert (
957
                page.tags['TileOffsets'].value[0]
958
                + page.tags['TileByteCounts'].value[0]
959
                == tif.filehandle.size
960
            )
961
            assert_array_equal(page.asarray(), data[0])
962
            assert_aszarr_method(page, data[0])
963
            assert__str__(tif)
964

965
    with TempFileName('issue_tile_partial_3d_separate') as fname:
966
        imwrite(
967
            fname,
968
            data,
969
            tile=(16, 16, 16),
970
            planarconfig=PLANARCONFIG.SEPARATE,
971
            photometric=PHOTOMETRIC.RGB,
972
        )
973
        with TiffFile(fname) as tif:
974
            assert len(tif.pages) == 1
975
            page = tif.pages.first
976
            assert not page.is_contiguous
977
            assert page.is_tiled
978
            assert (
979
                page.tags['TileOffsets'].value[0]
980
                + page.tags['TileByteCounts'].value[0] * 3
981
                == tif.filehandle.size
982
            )
983
            assert_array_equal(page.asarray(), data)
984
            assert_aszarr_method(page, data)
985
            assert__str__(tif)
986

987
    # test complete tile is contiguous
988
    data = random_data(numpy.uint8, (16, 16))
989
    with TempFileName('issue_tile_partial_not') as fname:
990
        imwrite(fname, data, tile=(16, 16))
991
        with TiffFile(fname) as tif:
992
            assert len(tif.pages) == 1
993
            page = tif.pages.first
994
            assert page.is_contiguous
995
            assert page.is_memmappable
996
            assert page.is_tiled
997
            assert (
998
                page.tags['TileOffsets'].value[0]
999
                + page.tags['TileByteCounts'].value[0]
1000
                == tif.filehandle.size
1001
            )
1002
            assert_array_equal(page.asarray(), data)
1003
            assert_aszarr_method(page, data)
1004
            assert__str__(tif)
1005

1006

1007
@pytest.mark.parametrize('compression', [1, 8])
1008
@pytest.mark.parametrize('samples', [1, 3])
1009
def test_issue_tiles_pad(samples, compression):
1010
    """Test tiles from iterator get padded."""
1011
    # https://github.com/cgohlke/tifffile/issues/38
1012
    if samples == 3:
1013
        data = numpy.random.randint(0, 2**12, (31, 33, 3), numpy.uint16)
1014
        photometric = 'rgb'
1015
    else:
1016
        data = numpy.random.randint(0, 2**12, (31, 33), numpy.uint16)
1017
        photometric = None
1018

1019
    def tiles(data, tileshape, pad=False):
1020
        for y in range(0, data.shape[0], tileshape[0]):
1021
            for x in range(0, data.shape[1], tileshape[1]):
1022
                tile = data[y : y + tileshape[0], x : x + tileshape[1]]
1023
                if pad and tile.shape != tileshape:
1024
                    tile = numpy.pad(
1025
                        tile,
1026
                        (
1027
                            (0, tileshape[0] - tile.shape[0]),
1028
                            (0, tileshape[1] - tile.shape[1]),
1029
                        ),
1030
                    )
1031
                yield tile
1032

1033
    with TempFileName(
1034
        f'issue_issue_tiles_pad_{compression}{samples}'
1035
    ) as fname:
1036
        imwrite(
1037
            fname,
1038
            tiles(data, (16, 16)),
1039
            dtype=data.dtype,
1040
            shape=data.shape,
1041
            tile=(16, 16),
1042
            photometric=photometric,
1043
            compression=compression,
1044
        )
1045
        assert_array_equal(imread(fname), data)
1046
        assert_valid_tiff(fname)
1047

1048

1049
def test_issue_fcontiguous():
1050
    """Test write F-contiguous arrays."""
1051
    # https://github.com/cgohlke/tifffile/issues/24
1052
    data = numpy.asarray(random_data(numpy.uint8, (31, 33)), order='F')
1053
    with TempFileName('issue_fcontiguous') as fname:
1054
        imwrite(fname, data, compression=COMPRESSION.ADOBE_DEFLATE)
1055
        with TiffFile(fname) as tif:
1056
            assert len(tif.pages) == 1
1057
            page = tif.pages.first
1058
            assert_array_equal(page.asarray(), data)
1059
            assert__str__(tif)
1060

1061

1062
def test_issue_pathlib():
1063
    """Test support for pathlib.Path."""
1064
    data = random_data(numpy.uint16, (219, 301))
1065
    with TempFileName('issue_pathlib') as fname:
1066
        fname = pathlib.Path(fname)
1067
        assert isinstance(fname, os.PathLike)
1068
        # imwrite
1069
        imwrite(fname, data)
1070
        # imread
1071
        im = imread(fname)
1072
        assert_array_equal(im, data)
1073
        # memmap
1074
        im = memmap(fname)
1075
        try:
1076
            assert_array_equal(im, data)
1077
        finally:
1078
            del im
1079
        # TiffFile
1080
        with TiffFile(fname) as tif:
1081
            with TempFileName('issue_pathlib_out') as outfname:
1082
                outfname = pathlib.Path(outfname)
1083
                # out=file
1084
                im = tif.asarray(out=outfname)
1085
                try:
1086
                    assert isinstance(im, numpy.memmap)
1087
                    assert_array_equal(im, data)
1088
                    assert os.path.samefile(im.filename, str(outfname))
1089
                finally:
1090
                    del im
1091
        # TiffSequence
1092
        with TiffSequence(fname) as tifs:
1093
            im = tifs.asarray()
1094
            assert_array_equal(im[0], data)
1095
        with TiffSequence([fname]) as tifs:
1096
            im = tifs.asarray()
1097
            assert_array_equal(im[0], data)
1098

1099
    # TiffSequence container
1100
    if SKIP_PRIVATE or SKIP_CODECS:
1101
        pytest.skip(REASON)
1102
    fname = pathlib.Path(private_file('TiffSequence.zip'))
1103
    with TiffSequence('*.tif', container=fname, pattern=None) as tifs:
1104
        im = tifs.asarray()
1105
        assert im[9, 256, 256] == 135
1106

1107

1108
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
1109
def test_issue_lzw_corrupt():
1110
    """Test decode corrupted LZW segment raises RuntimeError."""
1111
    # reported by S Richter on 2020.2.17
1112
    fname = private_file('issues/lzw_corrupt.tiff')
1113
    with pytest.raises(RuntimeError):
1114
        with TiffFile(fname) as tif:
1115
            tif.asarray()
1116

1117

1118
def test_issue_iterable_compression():
1119
    """Test write iterable of pages with compression."""
1120
    # https://github.com/cgohlke/tifffile/issues/20
1121
    data = numpy.random.rand(10, 10, 10) * 127
1122
    data = data.astype(numpy.int8)
1123
    with TempFileName('issue_iterable_compression') as fname:
1124
        with TiffWriter(fname) as tif:
1125
            tif.write(data, shape=(10, 10, 10), dtype=numpy.int8)
1126
            tif.write(
1127
                data,
1128
                shape=(10, 10, 10),
1129
                dtype=numpy.int8,
1130
                compression=COMPRESSION.ADOBE_DEFLATE,
1131
            )
1132
        with TiffFile(fname) as tif:
1133
            assert_array_equal(tif.series[0].asarray(), data)
1134
            assert_array_equal(tif.series[1].asarray(), data)
1135
    # fail with wrong dtype
1136
    with TempFileName('issue_iterable_compression_fail') as fname:
1137
        with TiffWriter(fname) as tif:
1138
            with pytest.raises(ValueError):
1139
                tif.write(data, shape=(10, 10, 10), dtype=numpy.uint8)
1140
        with TiffWriter(fname) as tif:
1141
            with pytest.raises(ValueError):
1142
                tif.write(
1143
                    data,
1144
                    shape=(10, 10, 10),
1145
                    dtype=numpy.uint8,
1146
                    compression=COMPRESSION.ADOBE_DEFLATE,
1147
                )
1148

1149

1150
def test_issue_write_separated():
1151
    """Test write SEPARATED colorspace."""
1152
    # https://github.com/cgohlke/tifffile/issues/37
1153
    contig = random_data(numpy.uint8, (63, 95, 4))
1154
    separate = random_data(numpy.uint8, (4, 63, 95))
1155
    extrasample = random_data(numpy.uint8, (63, 95, 5))
1156
    with TempFileName('issue_write_separated') as fname:
1157
        with TiffWriter(fname) as tif:
1158
            tif.write(contig, photometric=PHOTOMETRIC.SEPARATED)
1159
            tif.write(separate, photometric=PHOTOMETRIC.SEPARATED)
1160
            tif.write(
1161
                extrasample,
1162
                photometric=PHOTOMETRIC.SEPARATED,
1163
                extrasamples=[1],
1164
            )
1165
        assert_valid_tiff(fname)
1166
        with TiffFile(fname) as tif:
1167
            assert len(tif.pages) == 3
1168
            assert len(tif.series) == 3
1169
            page = tif.pages.first
1170
            assert page.photometric == PHOTOMETRIC.SEPARATED
1171
            assert_array_equal(page.asarray(), contig)
1172
            page = tif.pages[1]
1173
            assert page.photometric == PHOTOMETRIC.SEPARATED
1174
            assert_array_equal(page.asarray(), separate)
1175
            page = tif.pages[2]
1176
            assert page.photometric == PHOTOMETRIC.SEPARATED
1177
            assert page.extrasamples == (1,)
1178
            assert_array_equal(page.asarray(), extrasample)
1179

1180

1181
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
1182
def test_issue_mmap():
1183
    """Test read from mmap object with no readinto function.."""
1184
    fname = public_file('OME/bioformats-artificial/4D-series.ome.tiff')
1185
    with open(fname, 'rb') as fh:
1186
        mm = mmap.mmap(fh.fileno(), 0, access=mmap.ACCESS_READ)
1187
        assert_array_equal(imread(mm), imread(fname))
1188
        mm.close()
1189

1190

1191
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
1192
def test_issue_micromanager(caplog):
1193
    """Test fallback to ImageJ metadata if OME series fails."""
1194
    # https://github.com/cgohlke/tifffile/issues/54
1195
    # https://forum.image.sc/t/47567/9
1196
    # OME-XML does not contain reference to master file
1197
    # file has corrupted MicroManager DisplaySettings metadata
1198
    fname = private_file(
1199
        'OME/'
1200
        'image_stack_tpzc_50tp_2p_5z_3c_512k_1_MMStack_2-Pos001_000.ome.tif'
1201
    )
1202
    with TiffFile(
1203
        fname, is_mmstack=False, is_ndtiff=False, is_mdgel=False
1204
    ) as tif:
1205
        assert len(tif.pages) == 750
1206
        with caplog.at_level(logging.DEBUG):
1207
            assert len(tif.series) == 1
1208
            assert 'OME series is BinaryOnly' in caplog.text
1209
        assert tif.is_micromanager
1210
        assert tif.is_ome
1211
        assert tif.is_imagej
1212
        assert tif.micromanager_metadata is not None
1213
        assert 'DisplaySettings' not in tif.micromanager_metadata
1214
        assert 'failed to read display settings' not in caplog.text
1215
        series = tif.series[0]
1216
        assert series.shape == (50, 5, 3, 256, 256)
1217

1218

1219
@pytest.mark.skipif(IS_PYPY, reason=REASON)
1220
def test_issue_pickle():
1221
    """Test that TIFF constants are picklable."""
1222
    # https://github.com/cgohlke/tifffile/issues/64
1223
    from pickle import dumps, loads
1224

1225
    with pytest.warns(DeprecationWarning):
1226
        assert loads(dumps(TIFF)).CHUNKMODE.PLANE == TIFF.CHUNKMODE.PLANE
1227
        assert loads(dumps(TIFF.CHUNKMODE)).PLANE == TIFF.CHUNKMODE.PLANE
1228
        assert loads(dumps(TIFF.CHUNKMODE.PLANE)) == TIFF.CHUNKMODE.PLANE
1229

1230

1231
def test_issue_imagej_singlet_dimensions():
1232
    """Test that ImageJ files can be read preserving singlet dimensions."""
1233
    # https://github.com/cgohlke/tifffile/issues/19
1234
    # https://github.com/cgohlke/tifffile/issues/66
1235

1236
    data = numpy.random.randint(0, 2**8, (1, 10, 1, 248, 260, 1), numpy.uint8)
1237

1238
    with TempFileName('issue_imagej_singlet_dimensions') as fname:
1239
        imwrite(fname, data, imagej=True)
1240
        image = imread(fname, squeeze=False)
1241
        assert_array_equal(image, data)
1242

1243
        with TiffFile(fname) as tif:
1244
            assert tif.is_imagej
1245
            series = tif.series[0]
1246
            assert series.axes == 'ZYX'
1247
            assert series.shape == (10, 248, 260)
1248
            assert series.get_axes(squeeze=False) == 'TZCYXS'
1249
            assert series.get_shape(squeeze=False) == (1, 10, 1, 248, 260, 1)
1250
            data = tif.asarray(squeeze=False)
1251
            assert_array_equal(image, data)
1252
            assert_aszarr_method(series, data, squeeze=False)
1253
            assert_aszarr_method(series, data, squeeze=False, chunkmode='page')
1254

1255

1256
@pytest.mark.skipif(
1257
    SKIP_PRIVATE or SKIP_CODECS or not imagecodecs.JPEG.available,
1258
    reason=REASON,
1259
)
1260
def test_issue_cr2_ojpeg():
1261
    """Test read OJPEG image from CR2."""
1262
    # https://github.com/cgohlke/tifffile/issues/75
1263

1264
    fname = private_file('CanonCR2/Canon - EOS M6 - RAW (3 2).cr2')
1265

1266
    with TiffFile(fname) as tif:
1267
        assert len(tif.pages) == 4
1268
        page = tif.pages.first
1269
        assert page.compression == 6
1270
        assert page.shape == (4000, 6000, 3)
1271
        assert page.dtype == numpy.uint8
1272
        assert page.photometric == PHOTOMETRIC.YCBCR
1273
        assert page.compression == COMPRESSION.OJPEG
1274
        data = page.asarray()
1275
        assert data.shape == (4000, 6000, 3)
1276
        assert data.dtype == numpy.uint8
1277
        assert tuple(data[1640, 2372]) == (71, 75, 58)
1278
        assert_aszarr_method(page, data)
1279

1280
        page = tif.pages[1]
1281
        assert page.shape == (120, 160, 3)
1282
        assert page.dtype == numpy.uint8
1283
        assert page.photometric == PHOTOMETRIC.YCBCR
1284
        assert page.compression == COMPRESSION.OJPEG
1285
        data = page.asarray()
1286
        assert tuple(data[60, 80]) == (124, 144, 107)
1287
        assert_aszarr_method(page, data)
1288

1289
        page = tif.pages[2]
1290
        assert page.shape == (400, 600, 3)
1291
        assert page.dtype == numpy.uint16
1292
        assert page.photometric == PHOTOMETRIC.RGB
1293
        assert page.compression == COMPRESSION.NONE
1294
        data = page.asarray()
1295
        assert tuple(data[200, 300]) == (1648, 2340, 1348)
1296
        assert_aszarr_method(page, data)
1297

1298
        page = tif.pages[3]
1299
        assert page.shape == (4056, 3144, 2)
1300
        assert page.dtype == numpy.uint16
1301
        assert page.photometric == PHOTOMETRIC.MINISWHITE
1302
        assert page.compression == COMPRESSION.OJPEG  # SOF3
1303
        data = page.asarray()
1304
        assert tuple(data[2000, 1500]) == (1759, 2467)
1305
        assert_aszarr_method(page, data)
1306

1307

1308
@pytest.mark.skipif(
1309
    SKIP_PRIVATE or SKIP_CODECS or not imagecodecs.JPEG.available,
1310
    reason=REASON,
1311
)
1312
def test_issue_ojpeg_preview():
1313
    """Test read JPEGInterchangeFormat from RAW image."""
1314
    # https://github.com/cgohlke/tifffile/issues/93
1315

1316
    fname = private_file('RAW/RAW_NIKON_D3X.NEF')
1317

1318
    with TiffFile(fname) as tif:
1319
        assert len(tif.pages) == 1
1320
        page = tif.pages.first
1321
        assert page.compression == COMPRESSION.NONE
1322
        assert page.shape == (120, 160, 3)
1323
        assert page.dtype == numpy.uint8
1324
        assert page.photometric == PHOTOMETRIC.RGB
1325
        data = page.asarray()
1326
        assert data.shape == (120, 160, 3)
1327
        assert data.dtype == numpy.uint8
1328
        assert tuple(data[60, 80]) == (180, 167, 159)
1329
        assert_aszarr_method(page, data)
1330

1331
        page = tif.pages.first.pages[0]
1332
        assert page.shape == (4032, 6048, 3)
1333
        assert page.dtype == numpy.uint8
1334
        assert page.photometric == COMPRESSION.OJPEG
1335
        data = page.asarray()
1336
        assert tuple(data[60, 80]) == (67, 13, 11)
1337
        assert_aszarr_method(page, data)
1338

1339
        page = tif.pages.first.pages[1]
1340
        assert page.shape == (4044, 6080)
1341
        assert page.bitspersample == 14
1342
        assert page.photometric == PHOTOMETRIC.CFA
1343
        assert page.compression == COMPRESSION.NIKON_NEF
1344
        with pytest.raises(ValueError):
1345
            data = page.asarray()
1346

1347

1348
@pytest.mark.skipif(
1349
    SKIP_PRIVATE or SKIP_CODECS or not imagecodecs.JPEG.available,
1350
    reason=REASON,
1351
)
1352
def test_issue_arw(caplog):
1353
    """Test read Sony ARW RAW image."""
1354
    # https://github.com/cgohlke/tifffile/issues/95
1355

1356
    fname = private_file('RAW/A1_full_lossless_compressed.ARW')
1357

1358
    with TiffFile(fname) as tif:
1359
        assert len(tif.pages) == 3
1360
        assert len(tif.series) == 4
1361

1362
        page = tif.pages.first
1363
        assert page.compression == COMPRESSION.OJPEG
1364
        assert page.photometric == PHOTOMETRIC.YCBCR
1365
        assert page.shape == (1080, 1616, 3)
1366
        assert page.dtype == numpy.uint8
1367
        data = page.asarray()
1368
        assert data.shape == (1080, 1616, 3)
1369
        assert data.dtype == numpy.uint8
1370
        assert tuple(data[60, 80]) == (122, 119, 104)
1371
        assert_aszarr_method(page, data)
1372
        assert tif.pages.first.pages is not None
1373
        page = tif.pages.first.pages[0]
1374
        assert page.is_tiled
1375
        assert page.compression == COMPRESSION.JPEG
1376
        assert page.photometric == PHOTOMETRIC.CFA
1377
        assert page.bitspersample == 14
1378
        assert page.tags['SonyRawFileType'].value == 4
1379
        assert page.tags['CFARepeatPatternDim'].value == (2, 2)
1380
        assert page.tags['CFAPattern'].value == b'\0\1\1\2'
1381
        assert page.shape == (6144, 8704)
1382
        assert page.dtype == numpy.uint16
1383
        data = page.asarray()
1384
        assert 'SonyRawFileType' in caplog.text
1385
        assert data[60, 80] == 1000  # might not be correct according to #95
1386
        assert_aszarr_method(page, data)
1387

1388
        page = tif.pages[1]
1389
        assert page.compression == COMPRESSION.OJPEG
1390
        assert page.photometric == PHOTOMETRIC.YCBCR
1391
        assert page.shape == (120, 160, 3)
1392
        assert page.dtype == numpy.uint8
1393
        data = page.asarray()
1394
        assert tuple(data[60, 80]) == (56, 54, 29)
1395
        assert_aszarr_method(page, data)
1396

1397
        page = tif.pages[2]
1398
        assert page.compression == COMPRESSION.JPEG
1399
        assert page.photometric == PHOTOMETRIC.YCBCR
1400
        assert page.shape == (5760, 8640, 3)
1401
        assert page.dtype == numpy.uint8
1402
        data = page.asarray()
1403
        assert tuple(data[60, 80]) == (243, 238, 218)
1404
        assert_aszarr_method(page, data)
1405

1406

1407
def test_issue_rational_rounding():
1408
    """Test rational are rounded to 64-bit."""
1409
    # https://github.com/cgohlke/tifffile/issues/81
1410

1411
    data = numpy.array([[255]])
1412

1413
    with TempFileName('issue_rational_rounding') as fname:
1414
        imwrite(fname, data, resolution=(7411.824413635355, 7411.824413635355))
1415

1416
        with TiffFile(fname) as tif:
1417
            tags = tif.pages.first.tags
1418
            assert tags['XResolution'].value == (4294967295, 579475)
1419
            assert tags['YResolution'].value == (4294967295, 579475)
1420

1421

1422
def test_issue_omexml_micron():
1423
    """Test OME-TIFF can be created with micron character in XML."""
1424
    # https://forum.image.sc/t/micro-character-in-omexml-from-python/53578/4
1425

1426
    with TempFileName('issue_omexml_micron', ext='.ome.tif') as fname:
1427
        imwrite(
1428
            fname,
1429
            [[0]],
1430
            metadata={'PhysicalSizeX': 1.0, 'PhysicalSizeXUnit': 'µm'},
1431
        )
1432
        with TiffFile(fname) as tif:
1433
            assert tif.is_ome
1434
            assert (
1435
                'PhysicalSizeXUnit="µm"'
1436
                in tif.pages.first.tags['ImageDescription'].value
1437
            )
1438

1439

1440
def test_issue_svs_doubleheader():
1441
    """Test svs_description_metadata for SVS with double header."""
1442
    # https://github.com/cgohlke/tifffile/pull/88
1443

1444
    assert svs_description_metadata(
1445
        'Aperio Image Library v11.2.1\r\n'
1446
        '2220x2967 -> 574x768 - ;Aperio Image Library v10.0.51\r\n'
1447
        '46920x33014 [0,100 46000x32914] (256x256) JPEG/RGB Q=30'
1448
        '|AppMag = 20|StripeWidth = 2040|ScanScope ID = CPAPERIOCS'
1449
        '|Filename = CMU-1|Date = 12/29/09|Time = 09:59:15'
1450
        '|User = b414003d-95c6-48b0-9369-8010ed517ba7|Parmset = USM Filter'
1451
        '|MPP = 0.4990|Left = 25.691574|Top = 23.449873'
1452
        '|LineCameraSkew = -0.000424|LineAreaXOffset = 0.019265'
1453
        '|LineAreaYOffset = -0.000313|Focus Offset = 0.000000'
1454
        '|ImageID = 1004486|OriginalWidth = 46920|Originalheight = 33014'
1455
        '|Filtered = 5|OriginalWidth = 46000|OriginalHeight = 32914'
1456
    ) == {
1457
        'Header': (
1458
            'Aperio Image Library v11.2.1\r\n'
1459
            '2220x2967 -> 574x768 - ;Aperio Image Library v10.0.51\r\n'
1460
            '46920x33014 [0,100 46000x32914] (256x256) JPEG/RGB Q=30'
1461
        ),
1462
        'AppMag': 20,
1463
        'StripeWidth': 2040,
1464
        'ScanScope ID': 'CPAPERIOCS',
1465
        'Filename': 'CMU-1',
1466
        'Date': '12/29/09',
1467
        'Time': '09:59:15',
1468
        'User': 'b414003d-95c6-48b0-9369-8010ed517ba7',
1469
        'Parmset': 'USM Filter',
1470
        'MPP': 0.499,
1471
        'Left': 25.691574,
1472
        'Top': 23.449873,
1473
        'LineCameraSkew': -0.000424,
1474
        'LineAreaXOffset': 0.019265,
1475
        'LineAreaYOffset': -0.000313,
1476
        'Focus Offset': 0.0,
1477
        'ImageID': 1004486,
1478
        'OriginalWidth': 46000,
1479
        'Originalheight': 33014,
1480
        'Filtered': 5,
1481
        'OriginalHeight': 32914,
1482
    }
1483

1484

1485
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
1486
def test_issue_packbits_dtype():
1487
    """Test read and efficiently write PackBits compressed int16 image."""
1488
    # https://github.com/blink1073/tifffile/issues/61
1489
    # requires imagecodecs > 2021.6.8
1490

1491
    fname = private_file('packbits/imstack_packbits-int16.tif')
1492

1493
    with TiffFile(fname) as tif:
1494
        assert len(tif.pages) == 519
1495
        page = tif.pages[181]
1496
        assert page.compression == COMPRESSION.PACKBITS
1497
        assert page.photometric == PHOTOMETRIC.MINISBLACK
1498
        assert page.shape == (348, 185)
1499
        assert page.dtype == numpy.int16
1500
        data = page.asarray()
1501
        assert data.shape == (348, 185)
1502
        assert data.dtype == numpy.int16
1503
        assert data[184, 72] == 24
1504
        assert_aszarr_method(page, data)
1505
        data = tif.asarray()
1506
        assert_aszarr_method(tif, data)
1507

1508
    buf = BytesIO()
1509
    imwrite(buf, data, compression='packbits')
1510
    assert buf.seek(0, 2) < 1700000  # efficiently compressed
1511
    buf.seek(0)
1512

1513
    with TiffFile(buf) as tif:
1514
        assert len(tif.pages) == 519
1515
        page = tif.pages[181]
1516
        assert page.compression == COMPRESSION.PACKBITS
1517
        assert page.photometric == PHOTOMETRIC.MINISBLACK
1518
        assert page.shape == (348, 185)
1519
        assert page.dtype == numpy.int16
1520
        data = page.asarray()
1521
        assert data.shape == (348, 185)
1522
        assert data.dtype == numpy.int16
1523
        assert data[184, 72] == 24
1524
        assert_aszarr_method(page, data)
1525
        data = tif.asarray()
1526
        assert_aszarr_method(tif, data)
1527

1528

1529
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
1530
def test_issue_predictor_byteorder():
1531
    """Test read big-endian uint32 RGB with horizontal predictor."""
1532

1533
    fname = private_file('issues/flower-rgb-contig-32_msb_zip_predictor.tiff')
1534

1535
    with TiffFile(fname) as tif:
1536
        assert tif.tiff.byteorder == '>'
1537
        assert len(tif.pages) == 1
1538
        page = tif.pages.first
1539
        assert page.compression == COMPRESSION.ADOBE_DEFLATE
1540
        assert page.photometric == PHOTOMETRIC.RGB
1541
        assert page.predictor == PREDICTOR.HORIZONTAL
1542
        assert page.shape == (43, 73, 3)
1543
        assert page.dtype == numpy.uint32
1544
        data = page.asarray()
1545
        assert data.shape == (43, 73, 3)
1546
        assert data.dtype == numpy.uint32
1547
        assert tuple(data[30, 2]) == (0, 246337650, 191165795)
1548
        assert data.dtype.byteorder == '='
1549
        assert_aszarr_method(page, data)
1550
        data = tif.asarray()
1551
        assert_aszarr_method(tif, data)
1552

1553

1554
@pytest.mark.skipif(SKIP_ZARR or SKIP_DASK, reason=REASON)
1555
@pytest.mark.parametrize('truncate', [False, True])
1556
@pytest.mark.parametrize('chunkmode', [0, 2])
1557
def test_issue_dask_multipage(truncate, chunkmode):
1558
    """Test multi-threaded access of memory-mapable, multi-page Zarr stores."""
1559
    # https://github.com/cgohlke/tifffile/issues/67#issuecomment-908529425
1560
    data = numpy.arange(5 * 99 * 101, dtype=numpy.uint16).reshape((5, 99, 101))
1561
    with TempFileName(
1562
        f'issue_dask_multipage_{int(truncate)}_{chunkmode}'
1563
    ) as fname:
1564
        kwargs = {'truncate': truncate}
1565
        if not truncate:
1566
            kwargs['tile'] = (32, 32)
1567
        imwrite(fname, data, **kwargs)
1568
        with imread(fname, aszarr=True, chunkmode=chunkmode) as store:
1569
            daskarray = dask.array.from_zarr(store).compute()
1570
            assert_array_equal(data, daskarray)
1571

1572

1573
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_ZARR, reason=REASON)
1574
@pytest.mark.parametrize('chunkmode', [0, 2])
1575
def test_issue_zarr_store_closed(chunkmode):
1576
    """Test Zarr store filehandle is open when reading from unloaded pages."""
1577
    # https://github.com/cgohlke/tifffile/issues/67#issuecomment-2246367891
1578
    fname = private_file('ImageJ/_malaria_parasites.tif')
1579
    data = imread(fname)
1580
    store = imread(fname, aszarr=True, chunkmode=chunkmode)
1581
    try:
1582
        z = zarr.open(store, mode='r')
1583
        chunk = z[10:11, 3:-3]  # seek of closed file
1584
    finally:
1585
        store.close()
1586
    assert_array_equal(chunk, data[10:11, 3:-3])
1587

1588
    store = imread(fname, aszarr=True, chunkmode=chunkmode)
1589
    try:
1590
        z = zarr.open(store, mode='r')
1591
        chunk = z[:]
1592
    finally:
1593
        store.close()
1594
    assert_array_equal(chunk, data)
1595

1596

1597
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_ZARR, reason=REASON)
1598
@pytest.mark.parametrize('chunkmode', [0, 2])
1599
def test_issue_zarr_store_multifile_closed(chunkmode):
1600
    """Test Zarr store can read from closed files."""
1601
    fname = private_file('OME/tubhiswt-4D-lzw/tubhiswt_C0_T0.ome.tif')
1602
    data = imread(fname)
1603
    assert data.shape == (43, 10, 2, 512, 512)
1604
    store = imread(fname, aszarr=True, chunkmode=chunkmode)
1605
    try:
1606
        z = zarr.open(store, mode='r')
1607
        chunk = z[32:35, 3:7, :, 31:-31, 33:-33]  # seek of closed file
1608
    finally:
1609
        store.close()
1610
    assert_array_equal(chunk, data[32:35, 3:7, :, 31:-31, 33:-33])
1611

1612

1613
@pytest.mark.skipif(
1614
    SKIP_PRIVATE or SKIP_CODECS or not imagecodecs.LZW.available, reason=REASON
1615
)
1616
def test_issue_read_from_closed_file():
1617
    """Test read from closed file handles."""
1618
    fname = private_file('OME/tubhiswt-4D-lzw/tubhiswt_C0_T0.ome.tif')
1619
    with tifffile.TiffFile(fname) as tif:
1620
        count = 0
1621
        for frame in tif.series[0].pages[:10]:
1622
            # most file handles are closed
1623
            if frame is None:
1624
                continue
1625
            isclosed = frame.parent.filehandle.closed
1626
            if not isclosed:
1627
                continue
1628
            count += 1
1629

1630
            if isinstance(frame, TiffFrame):
1631
                with pytest.warns(UserWarning):
1632
                    page = frame.aspage()  # re-load frame as page
1633
                assert isclosed == page.parent.filehandle.closed
1634
            else:
1635
                page = frame
1636

1637
            with pytest.warns(UserWarning):
1638
                page.colormap  # delay load tag value
1639
            assert isclosed == page.parent.filehandle.closed
1640

1641
            with pytest.warns(UserWarning):
1642
                frame.asarray()  # read data
1643
            assert isclosed == page.parent.filehandle.closed
1644
        assert count > 0
1645

1646

1647
@pytest.mark.skipif(
1648
    SKIP_PRIVATE or SKIP_CODECS or not imagecodecs.PNG.available, reason=REASON
1649
)
1650
def test_issue_filesequence_categories(caplog):
1651
    """Test FileSequence with categories."""
1652
    # https://github.com/cgohlke/tifffile/issues/76
1653

1654
    with tifffile.FileSequence(
1655
        imagecodecs.imread,
1656
        private_file('dataset-A1-20200531/*.png'),
1657
        pattern=(
1658
            r'(?P<sampleid>.{2})-'
1659
            r'(?P<experiment>.+)-\d{8}T\d{6}-PSII0-'
1660
            r'(?P<frameid>\d)'
1661
        ),
1662
        categories={'sampleid': {'A1': 0, 'B1': 1}, 'experiment': {'doi': 0}},
1663
    ) as pngs:
1664
        with pytest.warns(DeprecationWarning):
1665
            assert len(pngs.files) == 2
1666
        assert len(pngs) == 2
1667
        assert pngs.files_missing == 2
1668
        assert pngs.shape == (2, 1, 2)
1669
        assert pngs.dims == ('sampleid', 'experiment', 'frameid')
1670
        data = pngs.asarray()
1671
        assert data.shape == (2, 1, 2, 200, 200)
1672
        assert data[1, 0, 1, 100, 100] == 353
1673

1674

1675
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
1676
def test_issue_filesequence_file_parameter():
1677
    """Test FileSequence.asarray with 'file' parameter removed in 2022.4.22."""
1678
    # https://github.com/bluesky/tiled/pull/97
1679

1680
    files = public_file('tifffile/temp_C001T00*.tif')
1681
    with TiffSequence(files) as tiffs:
1682
        assert tiffs.shape == (2,)
1683
        with pytest.raises(TypeError):
1684
            assert_array_equal(tiffs.asarray(file=files[0]), imread(files[0]))
1685
        with pytest.raises(TypeError):
1686
            assert_array_equal(tiffs.asarray(file=1), imread(files[1]))
1687

1688

1689
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
1690
def test_issue_imagej_prop():
1691
    """Test read and write ImageJ prop metadata type."""
1692
    # https://github.com/cgohlke/tifffile/issues/103
1693
    # also test write indexed ImageJ file
1694

1695
    fname = private_file('issues/triple-sphere-big-distance=035.tif')
1696
    with tifffile.TiffFile(fname) as tif:
1697
        assert tif.is_imagej
1698
        ijmeta = tif.imagej_metadata
1699
        assert ijmeta is not None
1700
        prop = ijmeta['Properties']
1701
        assert ijmeta['slices'] == 500
1702
        assert not ijmeta['loop']
1703
        assert prop['CurrentLUT'] == 'glasbey_on_dark'
1704
        assert tif.pages.first.photometric == PHOTOMETRIC.PALETTE
1705
        colormap = tif.pages.first.colormap
1706
        data = tif.asarray()
1707

1708
    prop['Test'] = 0.1
1709
    with TempFileName('issue_imagej_prop') as fname:
1710
        ijmeta['axes'] = 'ZYX'
1711
        imwrite(fname, data, imagej=True, colormap=colormap, metadata=ijmeta)
1712

1713
    with tifffile.TiffFile(fname) as tif:
1714
        assert tif.is_imagej
1715
        ijmeta = tif.imagej_metadata
1716
        assert ijmeta is not None
1717
        prop = ijmeta['Properties']
1718
        assert ijmeta['slices'] == 500
1719
        assert not ijmeta['loop']
1720
        assert prop['CurrentLUT'] == 'glasbey_on_dark'
1721
        assert prop['Test'] == '0.1'
1722
        assert tif.pages.first.photometric == PHOTOMETRIC.PALETTE
1723
        colormap = tif.pages.first.colormap
1724
        image = tif.asarray()
1725
        assert_array_equal(image, data)
1726

1727

1728
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
1729
def test_issue_missing_dataoffset(caplog):
1730
    """Test read file with missing data offset."""
1731
    fname = private_file('gdal/bigtiff_header_extract.tif')
1732
    with tifffile.TiffFile(fname) as tif:
1733
        page = tif.pages.first
1734
        assert page.imagewidth == 100000
1735
        assert page.imagelength == 100000
1736
        assert page.rowsperstrip == 1
1737
        assert page.databytecounts == (10000000000,)
1738
        assert page.dataoffsets == ()
1739
        assert 'incorrect StripOffsets count' in caplog.text
1740
        assert 'incorrect StripByteCounts count' in caplog.text
1741
        assert 'missing data offset tag' in caplog.text
1742
        with pytest.raises(TiffFileError):
1743
            tif.asarray()
1744

1745

1746
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
1747
def test_issue_imagej_metadatabytecounts():
1748
    """Test read ImageJ file with many IJMetadataByteCounts."""
1749
    # https://github.com/cgohlke/tifffile/issues/111
1750
    fname = private_file('imagej/issue111.tif')
1751
    with tifffile.TiffFile(fname) as tif:
1752
        assert tif.is_imagej
1753
        page = tif.pages.first
1754
        assert isinstance(page.tags['IJMetadataByteCounts'].value, tuple)
1755
        assert isinstance(page.tags['IJMetadata'].value, dict)
1756

1757

1758
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
1759
def test_issue_description_bytes():
1760
    """Test read file with imagedescription bytes."""
1761
    # https://github.com/cgohlke/tifffile/issues/112
1762
    with TempFileName('issue_description_bytes') as fname:
1763
        imwrite(
1764
            fname,
1765
            [[0]],
1766
            description='1st description',
1767
            extratags=[
1768
                ('ImageDescription', 1, None, b'\1\128\0', True),
1769
                ('ImageDescription', 1, None, b'\2\128\0', True),
1770
            ],
1771
            metadata=False,
1772
        )
1773
        with TiffFile(fname) as tif:
1774
            page = tif.pages.first
1775
            assert page.description == '1st description'
1776
            assert page.description1 == ''
1777
            assert page.tags.get(270).value == '1st description'
1778
            assert page.tags.get(270, index=1).value == b'\1\128\0'
1779
            assert page.tags.get(270, index=2).value == b'\2\128\0'
1780

1781

1782
def test_issue_imagej_colormap():
1783
    """Test write 32-bit imagej file with colormap."""
1784
    # https://github.com/cgohlke/tifffile/issues/115
1785
    colormap = numpy.vstack(
1786
        [
1787
            numpy.zeros(256, dtype=numpy.uint16),
1788
            numpy.arange(0, 2**16, 2**8, dtype=numpy.uint16),
1789
            numpy.arange(0, 2**16, 2**8, dtype=numpy.uint16),
1790
        ]
1791
    )
1792
    metadata = {'min': 0.0, 'max': 1.0, 'Properties': {'CurrentLUT': 'cyan'}}
1793
    with TempFileName('issue_imagej_colormap') as fname:
1794
        imwrite(
1795
            fname,
1796
            numpy.zeros((16, 16), numpy.float32),
1797
            imagej=True,
1798
            colormap=colormap,
1799
            metadata=metadata,
1800
        )
1801
        with TiffFile(fname) as tif:
1802
            assert tif.is_imagej
1803
            assert tif.imagej_metadata is not None
1804
            assert tif.imagej_metadata['Properties']['CurrentLUT'] == 'cyan'
1805
            assert tif.pages.first.photometric == PHOTOMETRIC.MINISBLACK
1806
            assert_array_equal(tif.pages.first.colormap, colormap)
1807

1808

1809
@pytest.mark.skipif(
1810
    SKIP_PRIVATE or SKIP_CODECS or not imagecodecs.WEBP.available,
1811
    reason=REASON,
1812
)
1813
@pytest.mark.parametrize('name', ['tile', 'strip'])
1814
def test_issue_webp_rgba(name, caplog):
1815
    """Test read WebP segments with missing alpha channel."""
1816
    # https://github.com/cgohlke/tifffile/issues/122
1817
    fname = private_file(f'issues/CMU-1-Small-Region.{name}.webp.tiff')
1818
    with tifffile.TiffFile(fname) as tif:
1819
        page = tif.pages.first
1820
        assert page.compression == COMPRESSION.WEBP
1821
        assert page.shape == (2967, 2220, 4)
1822
        assert tuple(page.asarray()[25, 25]) == (246, 244, 245, 255)
1823
        assert f'corrupted {name}' not in caplog.text
1824

1825

1826
@pytest.mark.skipif(
1827
    SKIP_PRIVATE or SKIP_ZARR or SKIP_CODECS or not imagecodecs.WEBP.available,
1828
    reason=REASON,
1829
)
1830
def test_issue_webp_fsspec():
1831
    """Test read WebP segments with missing alpha channel via fsspec."""
1832
    try:
1833
        from imagecodecs.numcodecs import register_codecs
1834
    except ImportError:
1835
        register_codecs = None
1836
    else:
1837
        register_codecs('imagecodecs_webp', verbose=False)
1838

1839
    fname = private_file('issues/CMU-1-Small-Region.tile.webp.tiff')
1840
    url = os.path.dirname(fname).replace('\\', '/')
1841
    data = imread(fname, series=0)
1842
    with TempFileName('issue_webp_fsspec', ext='.json') as jsonfile:
1843
        tiff2fsspec(
1844
            fname,
1845
            url,
1846
            out=jsonfile,
1847
            series=0,
1848
            level=0,
1849
            version=0,
1850
        )
1851
        mapper = fsspec.get_mapper(
1852
            'reference://',
1853
            fo=jsonfile,
1854
            target_protocol='file',
1855
            remote_protocol='file',
1856
        )
1857
        zobj = zarr.open(mapper, mode='r')
1858
        assert_array_equal(zobj[:], data)
1859

1860

1861
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_ZARR, reason=REASON)
1862
def test_issue_tiffslide():
1863
    """Test no ValueError when closing TiffSlide with Zarr group."""
1864
    # https://github.com/bayer-science-for-a-better-life/tiffslide/issues/25
1865
    try:
1866
        from tiffslide import TiffSlide
1867
    except ImportError:
1868
        pytest.skip('tiffslide missing')
1869

1870
    fname = private_file('AperioSVS/CMU-1.svs')
1871
    with TiffSlide(fname) as slide:
1872
        _ = slide.ts_zarr_grp
1873
        arr = slide.read_region((100, 200), 0, (256, 256), as_array=True)
1874
        assert arr.shape == (256, 256, 3)
1875

1876

1877
@pytest.mark.skipif(SKIP_ZARR, reason=REASON)
1878
def test_issue_xarray():
1879
    """Test read Zarr store with fsspec and xarray."""
1880
    try:
1881
        import xarray
1882
    except ImportError:
1883
        pytest.skip('xarray missing')
1884

1885
    data = numpy.random.randint(0, 2**8, (5, 31, 33, 3), numpy.uint8)
1886

1887
    with TempFileName('issue_xarry.ome') as fname:
1888
        with tifffile.TiffWriter(fname) as tif:
1889
            tif.write(
1890
                data,
1891
                photometric='rgb',
1892
                tile=(16, 16),
1893
                metadata={'axes': 'TYXC'},
1894
            )
1895

1896
        for squeeze in (True, False):
1897
            with TempFileName(
1898
                f'issue_xarry_{squeeze}', ext='.json'
1899
            ) as jsonfile:
1900
                with tifffile.TiffFile(fname) as tif:
1901
                    store = tif.series[0].aszarr(squeeze=squeeze)
1902
                    store.write_fsspec(
1903
                        jsonfile,
1904
                        url=os.path.split(jsonfile)[0],
1905
                        groupname='x',
1906
                    )
1907
                    store.close()
1908

1909
                mapper = fsspec.get_mapper(
1910
                    'reference://',
1911
                    fo=jsonfile,
1912
                    target_protocol='file',
1913
                    remote_protocol='file',
1914
                )
1915
                dataset = xarray.open_dataset(
1916
                    mapper,
1917
                    engine='zarr',
1918
                    mask_and_scale=False,
1919
                    backend_kwargs={'consolidated': False},
1920
                )
1921

1922
                if squeeze:
1923
                    assert dataset['x'].shape == (5, 31, 33, 3)
1924
                    assert dataset['x'].dims == ('T', 'Y', 'X', 'S')
1925
                else:
1926
                    assert dataset['x'].shape == (5, 1, 1, 31, 33, 3)
1927
                    assert dataset['x'].dims == ('T', 'Z', 'C', 'Y', 'X', 'S')
1928

1929
                assert_array_equal(data, numpy.squeeze(dataset['x'][:]))
1930
                del dataset
1931
                del mapper
1932

1933

1934
@pytest.mark.skipif(SKIP_ZARR, reason=REASON)
1935
def test_issue_xarray_multiscale():
1936
    """Test read multiscale Zarr store with fsspec and xarray."""
1937
    try:
1938
        import xarray
1939
    except ImportError:
1940
        pytest.skip('xarray missing')
1941

1942
    data = numpy.random.randint(0, 2**8, (8, 3, 128, 128), numpy.uint8)
1943

1944
    with TempFileName('issue_xarry_multiscale.ome') as fname:
1945
        with tifffile.TiffWriter(fname) as tif:
1946
            tif.write(
1947
                data,
1948
                photometric='rgb',
1949
                planarconfig='separate',
1950
                tile=(32, 32),
1951
                subifds=2,
1952
                metadata={'axes': 'TCYX'},
1953
            )
1954
            tif.write(
1955
                data[:, :, ::2, ::2],
1956
                photometric='rgb',
1957
                planarconfig='separate',
1958
                tile=(32, 32),
1959
            )
1960
            tif.write(
1961
                data[:, :, ::4, ::4],
1962
                photometric='rgb',
1963
                planarconfig='separate',
1964
                tile=(16, 16),
1965
            )
1966

1967
        for squeeze in (True, False):
1968
            with TempFileName(
1969
                f'issue_xarry_multiscale_{squeeze}', ext='.json'
1970
            ) as jsonfile:
1971
                with tifffile.TiffFile(fname) as tif:
1972
                    store = tif.series[0].aszarr(squeeze=squeeze)
1973
                    store.write_fsspec(
1974
                        jsonfile,
1975
                        url=os.path.split(jsonfile)[0],
1976
                        # groupname='test',
1977
                    )
1978
                    store.close()
1979

1980
                mapper = fsspec.get_mapper(
1981
                    'reference://',
1982
                    fo=jsonfile,
1983
                    target_protocol='file',
1984
                    remote_protocol='file',
1985
                )
1986
                dataset = xarray.open_dataset(
1987
                    mapper,
1988
                    engine='zarr',
1989
                    mask_and_scale=False,
1990
                    backend_kwargs={'consolidated': False},
1991
                )
1992
                if squeeze:
1993
                    assert dataset['0'].shape == (8, 3, 128, 128)
1994
                    assert dataset['0'].dims == ('T', 'S', 'Y', 'X')
1995
                    assert dataset['2'].shape == (8, 3, 32, 32)
1996
                    assert dataset['2'].dims == ('T', 'S', 'Y2', 'X2')
1997
                else:
1998
                    assert dataset['0'].shape == (8, 1, 1, 3, 128, 128)
1999
                    assert dataset['0'].dims == ('T', 'Z', 'C', 'S', 'Y', 'X')
2000
                    assert dataset['2'].shape == (8, 1, 1, 3, 32, 32)
2001
                    assert dataset['2'].dims == (
2002
                        'T',
2003
                        'Z',
2004
                        'C',
2005
                        'S',
2006
                        'Y2',
2007
                        'X2',
2008
                    )
2009

2010
                assert_array_equal(data, numpy.squeeze(dataset['0'][:]))
2011
                assert_array_equal(
2012
                    data[:, :, ::4, ::4], numpy.squeeze(dataset['2'][:])
2013
                )
2014
                del dataset
2015
                del mapper
2016

2017

2018
@pytest.mark.parametrize('resolution', [(1, 0), (0, 0)])
2019
def test_issue_invalid_resolution(resolution):
2020
    # https://github.com/imageio/imageio/blob/master/tests/test_tifffile.py
2021

2022
    data = numpy.zeros((20, 10), dtype=numpy.uint8)
2023

2024
    with TempFileName(f'issue_invalid_resolution{resolution[0]}') as fname:
2025
        imwrite(fname, data)
2026

2027
        with TiffFile(fname, mode='r+') as tif:
2028
            tags = tif.pages.first.tags
2029
            tags['XResolution'].overwrite(resolution)
2030
            tags['YResolution'].overwrite(resolution)
2031

2032
        with tifffile.TiffFile(fname) as tif:
2033
            tags = tif.pages.first.tags
2034
            assert tags['XResolution'].value == resolution
2035
            assert tags['YResolution'].value == resolution
2036
            assert__str__(tif)
2037

2038

2039
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
2040
def test_issue_indexing():
2041
    """Test indexing methods."""
2042
    fname = public_file('tifffile/multiscene_pyramidal.ome.tif')
2043
    data0 = imread(fname)
2044
    assert isinstance(data0, numpy.ndarray)
2045
    assert data0.shape == (16, 32, 2, 256, 256)
2046
    level1 = imread(fname, level=1)
2047
    assert isinstance(level1, numpy.ndarray)
2048
    assert level1.shape == (16, 32, 2, 128, 128)
2049
    data1 = imread(fname, series=1)
2050
    assert isinstance(data1, numpy.ndarray)
2051
    assert data1.shape == (128, 128, 3)
2052

2053
    assert_array_equal(data1, imread(fname, key=1024))
2054
    assert_array_equal(data1, imread(fname, key=[1024]))
2055
    assert_array_equal(data1, imread(fname, key=range(1024, 1025)))
2056
    assert_array_equal(data1, imread(fname, series=1, key=0))
2057
    assert_array_equal(data1, imread(fname, series=1, key=[0]))
2058
    assert_array_equal(
2059
        data1, imread(fname, series=1, level=0, key=slice(None))
2060
    )
2061

2062
    assert_array_equal(data0, imread(fname, series=0))
2063
    assert_array_equal(
2064
        data0.reshape(-1, 256, 256), imread(fname, series=0, key=slice(None))
2065
    )
2066
    assert_array_equal(
2067
        data0.reshape(-1, 256, 256), imread(fname, key=slice(0, -1, 1))
2068
    )
2069
    assert_array_equal(
2070
        data0.reshape(-1, 256, 256), imread(fname, key=range(1024))
2071
    )
2072
    assert_array_equal(data0[0, 0], imread(fname, key=[0, 1]))
2073
    assert_array_equal(data0[0, 0], imread(fname, series=0, key=(0, 1)))
2074

2075
    assert_array_equal(
2076
        level1.reshape(-1, 128, 128),
2077
        imread(fname, series=0, level=1, key=slice(None)),
2078
    )
2079
    assert_array_equal(
2080
        level1.reshape(-1, 128, 128),
2081
        imread(fname, series=0, level=1, key=range(1024)),
2082
    )
2083

2084

2085
def test_issue_shaped_metadata():
2086
    """Test shaped_metadata property."""
2087
    # https://github.com/cgohlke/tifffile/issues/127
2088
    shapes = ([5, 33, 31], [31, 33, 3])
2089
    with TempFileName('issue_shaped_metadata') as fname:
2090
        with TiffWriter(fname) as tif:
2091
            for shape in shapes:
2092
                tif.write(
2093
                    shape=shape,
2094
                    dtype=numpy.uint8,
2095
                    metadata={'comment': 'a comment', 'number': 42},
2096
                )
2097
        with TiffFile(fname) as tif:
2098
            assert tif.is_shaped
2099
            assert len(tif.series) == 2
2100
            assert tif.series[0].kind == 'shaped'
2101
            assert tif.series[1].kind == 'shaped'
2102
            meta = tif.shaped_metadata
2103
            assert meta is not None
2104
            assert len(meta) == 2
2105
            assert meta[0]['shape'] == shapes[0]
2106
            assert meta[0]['comment'] == 'a comment'
2107
            assert meta[0]['number'] == 42
2108
            assert meta[1]['shape'] == shapes[1]
2109
            assert meta[1]['comment'] == 'a comment'
2110
            assert meta[1]['number'] == 42
2111

2112

2113
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
2114
def test_issue_uic_dates(caplog):
2115
    """Test read MetaMorph STK metadata with invalid julian dates."""
2116
    # https://github.com/cgohlke/tifffile/issues/129
2117
    fname = private_file('issues/Cells-003_Cycle00001_Ch1_000001.ome.tif')
2118
    with TiffFile(fname) as tif:
2119
        assert tif.is_stk
2120
        assert tif.is_ome
2121
        assert tif.byteorder == '<'
2122
        assert len(tif.pages) == 1
2123
        # assert page properties
2124
        page = tif.pages.first
2125
        assert page.is_memmappable
2126
        assert page.shape == (256, 256)
2127
        assert page.tags['Software'].value == 'Prairie View 5.4.64.40'
2128
        assert page.tags['DateTime'].value == '2019:03:18 10:13:33'
2129
        # assert uic tags
2130
        with pytest.warns(RuntimeWarning):
2131
            meta = tif.stk_metadata
2132
        assert 'no datetime before year 1' in caplog.text
2133
        assert meta is not None
2134
        assert meta['CreateTime'] is None
2135
        assert meta['LastSavedTime'] is None
2136
        assert meta['DatetimeCreated'] is None
2137
        assert meta['DatetimeModified'] is None
2138
        assert meta['Name'] == 'Gattaca'
2139
        assert meta['NumberPlanes'] == 1
2140
        # assert meta['TimeCreated'] ...
2141
        # assert meta['TimeModified'] ...
2142
        assert meta['Wavelengths'][0] == 1.7906976744186047
2143

2144

2145
def test_issue_subfiletype_zero():
2146
    """Test write NewSubfileType=0."""
2147
    # https://github.com/cgohlke/tifffile/issues/132
2148
    with TempFileName('issue_subfiletype_zero') as fname:
2149
        imwrite(fname, [[0]], subfiletype=0)
2150
        with TiffFile(fname) as tif:
2151
            assert (
2152
                tif.pages.first.tags['NewSubfileType'].value
2153
                == FILETYPE.UNDEFINED
2154
            )
2155

2156

2157
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
2158
def test_issue_imagej_zct_order(caplog):
2159
    """Test read ImageJ hyperstack with non-TZC order."""
2160
    # https://forum.image.sc/t/69430
2161
    fname = private_file(
2162
        'MMStack/mosaic/d220708_HybISS_AS_cycles1to5_NoBridgeProbes_'
2163
        'dim3x3__3_MMStack_2-Pos_000_000.ome.tif'
2164
    )
2165
    data = imread(fname, series=5, is_mmstack=False)
2166

2167
    fname = private_file(
2168
        'MMStack/mosaic/d220708_HybISS_AS_cycles1to5_NoBridgeProbes_'
2169
        'dim3x3__3_MMStack_2-Pos_000_001.ome.tif'
2170
    )
2171
    with TiffFile(fname, is_mmstack=False) as tif:
2172
        assert not tif.is_mmstack
2173
        assert tif.is_ome
2174
        assert tif.is_imagej
2175
        assert tif.imagej_metadata is not None
2176
        assert tif.imagej_metadata['order'] == 'zct'
2177
        with caplog.at_level(logging.DEBUG):
2178
            series = tif.series[0]
2179
            assert 'OME series is BinaryOnly' in caplog.text
2180
        assert series.axes == 'CZYX'
2181
        assert series.kind == 'imagej'
2182
        assert_array_equal(series.asarray(), data)
2183

2184

2185
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
2186
def test_issue_fei_sfeg_metadata():
2187
    """Test read FEI_SFEG metadata."""
2188
    # https://github.com/cgohlke/tifffile/pull/141
2189
    # FEI_SFEG tag value is a base64 encoded XML string with BOM header
2190
    fname = private_file('issues/Helios-AutoSliceAndView.tif')
2191
    with TiffFile(fname) as tif:
2192
        fei = tif.fei_metadata
2193
        assert fei is not None
2194
        assert fei['User']['User'] == 'Supervisor'
2195
        assert fei['System']['DisplayHeight'] == 0.324
2196

2197

2198
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
2199
def test_issue_resolution():
2200
    """Test consistency of reading and writing resolution."""
2201
    resolution = (4294967295 / 3904515723, 4294967295 / 1952257861)  # 1.1, 2.2
2202
    resolutionunit = RESUNIT.CENTIMETER
2203
    scale = 111.111
2204
    with TempFileName('issue_resolution') as fname:
2205
        imwrite(
2206
            fname, [[0]], resolution=resolution, resolutionunit=resolutionunit
2207
        )
2208
        with TiffFile(fname) as tif:
2209
            page = tif.pages.first
2210
            assert tif.pages.first.tags['XResolution'].value == (
2211
                4294967295,
2212
                3904515723,
2213
            )
2214
            assert tif.pages.first.tags['YResolution'].value == (
2215
                4294967295,
2216
                1952257861,
2217
            )
2218
            assert tif.pages.first.tags['ResolutionUnit'].value == (
2219
                resolutionunit
2220
            )
2221

2222
            assert page.resolution == resolution
2223
            assert page.resolutionunit == resolutionunit
2224

2225
            assert page.get_resolution() == resolution
2226
            assert page.get_resolution(resolutionunit) == resolution
2227
            assert_array_almost_equal(
2228
                page.get_resolution(RESUNIT.MICROMETER),
2229
                (resolution[0] / 10000, resolution[1] / 10000),
2230
            )
2231
            assert_array_almost_equal(
2232
                page.get_resolution(RESUNIT.MICROMETER, 100),
2233
                (resolution[0] / 10000, resolution[1] / 10000),
2234
            )
2235
            assert_array_almost_equal(
2236
                page.get_resolution('inch'),
2237
                (resolution[0] * 2.54, resolution[1] * 2.54),
2238
            )
2239
            assert_array_almost_equal(
2240
                page.get_resolution(scale=111.111),
2241
                (resolution[0] * scale, resolution[1] * scale),
2242
            )
2243

2244

2245
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
2246
def test_issue_resolutionunit():
2247
    """Test write resolutionunit defaults."""
2248
    # https://github.com/cgohlke/tifffile/issues/145
2249

2250
    with TempFileName('issue_resolutionunit_none') as fname:
2251
        imwrite(fname, [[0]], resolution=None, resolutionunit=None)
2252
        with TiffFile(fname) as tif:
2253
            page = tif.pages.first
2254
            assert tif.pages.first.tags['ResolutionUnit'].value == RESUNIT.NONE
2255
            assert page.resolutionunit == RESUNIT.NONE
2256
            assert page.resolution == (1, 1)
2257

2258
    with TempFileName('issue_resolutionunit_inch') as fname:
2259
        imwrite(fname, [[0]], resolution=(1, 1), resolutionunit=None)
2260
        with TiffFile(fname) as tif:
2261
            page = tif.pages.first
2262
            assert tif.pages.first.tags['ResolutionUnit'].value == RESUNIT.INCH
2263
            assert page.resolutionunit == RESUNIT.INCH
2264
            assert page.resolution == (1, 1)
2265

2266
    with TempFileName('issue_resolutionunit_imagej') as fname:
2267
        imwrite(
2268
            fname, [[0]], dtype=numpy.float32, imagej=True, resolution=(1, 1)
2269
        )
2270
        with TiffFile(fname) as tif:
2271
            page = tif.pages.first
2272
            assert tif.pages.first.tags['ResolutionUnit'].value == RESUNIT.NONE
2273
            assert page.resolutionunit == RESUNIT.NONE
2274
            assert page.resolution == (1, 1)
2275

2276

2277
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
2278
def test_issue_ome_jpeg_colorspace():
2279
    """Test colorspace of JPEG segments encoded by BioFormats."""
2280
    # https://forum.image.sc/t/69862
2281
    # JPEG encoded segments are stored as YCBCR but the
2282
    # PhotometricInterpretation tag is RGB
2283
    # CMU-1.svs exported by QuPath 0.3.2
2284
    fname = private_file('ome/CMU-1.ome.tif')
2285
    with TiffFile(fname) as tif:
2286
        assert tif.is_ome
2287
        series = tif.series[0].levels[5]
2288
        assert series.kind == 'ome'
2289
        assert series.keyframe.is_jfif
2290
        assert series.shape == (1028, 1437, 3)
2291
        assert tuple(series.asarray()[800, 200]) == (207, 166, 198)
2292

2293

2294
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
2295
def test_issue_imagej_compressed():
2296
    """Test read ImageJ hyperstack with compression."""
2297
    # regression in tifffile 2022.7.28
2298
    fname = private_file('imagej/imagej_compressed.tif')
2299
    with TiffFile(fname) as tif:
2300
        assert tif.is_imagej
2301
        assert len(tif.pages) == 120
2302
        series = tif.series[0]
2303
        assert series.kind == 'imagej'
2304
        assert series.axes == 'ZCYX'
2305
        assert series.shape == (60, 2, 256, 256)
2306
        assert series.sizes == {
2307
            'depth': 60,
2308
            'channel': 2,
2309
            'height': 256,
2310
            'width': 256,
2311
        }
2312
        assert series.keyframe.compression == COMPRESSION.ADOBE_DEFLATE
2313
        assert series.asarray()[59, 1, 55, 87] == 5643
2314

2315

2316
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_CODECS, reason=REASON)
2317
def test_issue_jpeg_rgb():
2318
    """Test write JPEG compression in RGB mode."""
2319
    # https://github.com/cgohlke/tifffile/issues/146
2320
    # requires imagecodecs > 2022.7.31
2321
    data = imread(public_file('tifffile/rgb.tif'))
2322
    assert data.shape == (32, 31, 3)
2323
    with TempFileName('issue_jpeg_rgb') as fname:
2324
        imwrite(
2325
            fname,
2326
            data,
2327
            photometric='rgb',
2328
            subsampling=(1, 1),
2329
            compression='jpeg',
2330
            compressionargs={'level': 95, 'outcolorspace': 'rgb'},
2331
        )
2332
        with TiffFile(fname) as tif:
2333
            page = tif.pages.first
2334
            assert page.shape == data.shape
2335
            assert page.photometric == PHOTOMETRIC.RGB
2336
            assert page.compression == COMPRESSION.JPEG
2337
            assert not page.is_jfif
2338
            image = page.asarray()
2339
        assert_array_equal(image, imagecodecs.imread(fname))
2340

2341

2342
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
2343
def test_issue_imread_out():
2344
    """Test imread supports out argument."""
2345
    # https://github.com/cgohlke/tifffile/issues/147
2346
    fname = public_file('tifffile/rgb.tif')
2347
    image = imread(fname, out=None)
2348
    assert isinstance(image, numpy.ndarray)
2349
    data = imread(fname, out='memmap')
2350
    assert isinstance(data, numpy.memmap)
2351
    assert_array_equal(data, image)
2352

2353
    image = imread([fname, fname], out=None)
2354
    assert isinstance(image, numpy.ndarray)
2355
    assert_array_equal(image[1], data)
2356

2357
    data = imread(
2358
        [fname, fname],
2359
        chunkshape=(32, 31, 3),
2360
        chunkdtype=numpy.uint8,
2361
        out_inplace=True,
2362
        out='memmap',
2363
    )
2364
    assert isinstance(data, numpy.memmap)
2365
    assert_array_equal(data, image)
2366

2367

2368
def test_issue_imagej_hyperstack_arg():
2369
    """Test write ImageJ with hyperstack argument."""
2370
    # https://stackoverflow.com/questions/73279086
2371
    with TempFileName('issue_imagej_hyperstack_arg') as fname:
2372
        data = numpy.zeros((4, 3, 10, 11), dtype=numpy.uint8)
2373
        imwrite(
2374
            fname,
2375
            data,
2376
            imagej=True,
2377
            metadata={'hyperstack': True, 'axes': 'TZYX'},
2378
        )
2379
        with TiffFile(fname) as tif:
2380
            assert tif.is_imagej
2381
            assert 'hyperstack=true' in tif.pages.first.description
2382
            assert tif.imagej_metadata is not None
2383
            assert tif.imagej_metadata['hyperstack']
2384
            assert tif.series[0].axes == 'TZYX'
2385

2386

2387
def test_issue_description_overwrite():
2388
    """Test user description is not overwritten if metadata is disabled."""
2389
    data = numpy.zeros((5, 10, 11), dtype=numpy.uint8)
2390
    omexml = OmeXml()
2391
    omexml.addimage(
2392
        dtype=data.dtype,
2393
        shape=data.shape,
2394
        storedshape=(5, 1, 1, 10, 11, 1),
2395
        axes='ZYX',
2396
    )
2397
    description = omexml.tostring()
2398

2399
    with TempFileName('issue_description_overwrite') as fname:
2400
        with tifffile.TiffWriter(fname, ome=False) as tif:
2401
            for frame in data:
2402
                tif.write(
2403
                    frame,
2404
                    description=description,
2405
                    metadata=None,
2406
                    contiguous=True,
2407
                )
2408
                description = None
2409
        with TiffFile(fname) as tif:
2410
            assert tif.is_ome
2411
            assert tif.pages.first.description == omexml.tostring()
2412
            assert tif.series[0].kind == 'ome'
2413
            assert tif.series[0].axes == 'ZYX'
2414
            assert_array_equal(tif.asarray(), data)
2415

2416

2417
def test_issue_svs_description():
2418
    """Test svs_description_metadata function."""
2419
    # https://github.com/cgohlke/tifffile/issues/149
2420
    assert svs_description_metadata(
2421
        'Aperio Image Library vFS90 01\r\n'
2422
        '159712x44759 [0,100 153271x44659] (256x256) JPEG/RGB Q=30'
2423
        '|AppMag = 40'
2424
        '|StripeWidth = 992'
2425
        '|ScanScope ID = SS1475'
2426
        '|Filename = 12-0893-1'
2427
        '|Title = Mag = 40X, compression quality =30'
2428
        '|Date = 11/20/12'
2429
        '|Time = 01:06:12'
2430
        '|Time Zone = GMT-05:00'
2431
        '|User = 8ce982e3-6ea2-4715-8af3-9874e823e6d9'
2432
        '|MPP = 0.2472'
2433
        '|Left = 19.730396'
2434
        '|Top = 15.537785'
2435
        '|LineCameraSkew = 0.001417'
2436
        '|LineAreaXOffset = 0.014212'
2437
        '|LineAreaYOffset = -0.004733'
2438
        '|Focus Offset = 0.000000'
2439
        '|DSR ID = 152.19.62.167'
2440
        '|ImageID = 311112'
2441
        '|Exposure Time = 109'
2442
        '|Exposure Scale = 0.000001'
2443
        '|DisplayColor = 0'
2444
        '|OriginalWidth = 159712'
2445
        '|OriginalHeight = 44759'
2446
        '|ICC Profile = ScanScope v1'
2447
    ) == {
2448
        'Header': (
2449
            'Aperio Image Library vFS90 01\r\n'
2450
            '159712x44759 [0,100 153271x44659] (256x256) JPEG/RGB Q=30'
2451
        ),
2452
        'AppMag': 40,
2453
        'StripeWidth': 992,
2454
        'ScanScope ID': 'SS1475',
2455
        'Filename': '12-0893-1',
2456
        'Title': 'Mag = 40X, compression quality =30',
2457
        'Date': '11/20/12',
2458
        'Time': '01:06:12',
2459
        'Time Zone': 'GMT-05:00',
2460
        'User': '8ce982e3-6ea2-4715-8af3-9874e823e6d9',
2461
        'MPP': 0.2472,
2462
        'Left': 19.730396,
2463
        'Top': 15.537785,
2464
        'LineCameraSkew': 0.001417,
2465
        'LineAreaXOffset': 0.014212,
2466
        'LineAreaYOffset': -0.004733,
2467
        'Focus Offset': 0.0,
2468
        'DSR ID': '152.19.62.167',
2469
        'ImageID': 311112,
2470
        'Exposure Time': 109,
2471
        'Exposure Scale': 0.000001,
2472
        'DisplayColor': 0,
2473
        'OriginalWidth': 159712,
2474
        'OriginalHeight': 44759,
2475
        'ICC Profile': 'ScanScope v1',
2476
    }
2477

2478
    assert svs_description_metadata(
2479
        'Aperio Image Library v11.0.37\r\n60169x38406 (256x256) JPEG/RGB Q=70'
2480
        '|Patient=CS-10-SI_HE'
2481
        '|Accession='
2482
        '|User='
2483
        '|Date=10/12/2012'
2484
        '|Time=04:55:13 PM'
2485
        '|Copyright=Hamamatsu Photonics KK'
2486
        '|AppMag=20'
2487
        '|Webslide Files=5329'
2488
    ) == {
2489
        'Header': (
2490
            'Aperio Image Library v11.0.37\r\n'
2491
            '60169x38406 (256x256) JPEG/RGB Q=70'
2492
        ),
2493
        'Patient': 'CS-10-SI_HE',
2494
        'Accession': '',
2495
        'User': '',
2496
        'Date': '10/12/2012',
2497
        'Time': '04:55:13 PM',
2498
        'Copyright': 'Hamamatsu Photonics KK',
2499
        'AppMag': 20,
2500
        'Webslide Files': 5329,
2501
    }
2502

2503

2504
def test_issue_iterator_recursion():
2505
    """Test no RecursionError writing large number of tiled pages."""
2506
    with TempFileName('issue_iterator_recursion') as fname:
2507
        imwrite(fname, shape=(1024, 54, 64), dtype=numpy.uint8, tile=(32, 32))
2508

2509

2510
@pytest.mark.skipif(SKIP_CODECS, reason=REASON)
2511
def test_issue_predictor_floatx2():
2512
    """Test floatx2 predictor."""
2513
    # https://github.com/cgohlke/tifffile/issues/167
2514
    data = random_data(numpy.float32, (219, 302))
2515
    with TempFileName('issue_predictor_floatx2') as fname:
2516
        imwrite(fname, data, predictor=34894, compression=True)
2517
        with TiffFile(fname) as tif:
2518
            assert len(tif.pages) == 1
2519
            assert len(tif.series) == 1
2520
            page = tif.pages.first
2521
            assert page.photometric == PHOTOMETRIC.MINISBLACK
2522
            assert page.imagewidth == 302
2523
            assert page.imagelength == 219
2524
            assert page.samplesperpixel == 1
2525
            assert page.predictor == 34894
2526
            assert page.compression == 8
2527
            image = page.asarray()
2528
            assert_array_equal(data, image)
2529
            assert__str__(tif)
2530

2531

2532
@pytest.mark.skipif(SKIP_CODECS, reason=REASON)
2533
def test_issue_predictor_deltax2():
2534
    """Test deltax2 predictor."""
2535
    # https://github.com/cgohlke/tifffile/issues/167
2536
    data = random_data(numpy.uint8, (219, 302))
2537
    with TempFileName('issue_predictor_deltax2') as fname:
2538
        with pytest.raises(NotImplementedError):
2539
            imwrite(fname, data, predictor=34892, compression=8)
2540
        # with TiffFile(fname) as tif:
2541
        #     assert len(tif.pages) == 1
2542
        #     assert len(tif.series) == 1
2543
        #     page = tif.pages.first
2544
        #     assert page.photometric == MINISBLACK
2545
        #     assert page.imagewidth == 302
2546
        #     assert page.imagelength == 219
2547
        #     assert page.samplesperpixel == 1
2548
        #     assert page.predictor == 34892
2549
        #     assert page.compression == 8
2550
        #     image = page.asarray()
2551
        #     assert_array_equal(data, image)
2552
        #     assert__str__(tif)
2553

2554

2555
@pytest.mark.skipif(SKIP_CODECS, reason=REASON)
2556
@pytest.mark.parametrize('compression', ['none', 'packbits', 'zlib', 'lzw'])
2557
@pytest.mark.parametrize('predictor', ['none', 'horizontal'])
2558
@pytest.mark.parametrize('samples', [0, 1, 3])
2559
def test_issue_tile_generator(compression, predictor, samples):
2560
    """Test predictor and compression axes with tile generator."""
2561
    # https://github.com/cgohlke/tifffile/issues/185
2562

2563
    if compression == 'none' and predictor != 'none':
2564
        pytest.xfail('cannot use predictor without compression')
2565

2566
    data = numpy.empty(
2567
        (27, 23, samples) if samples else (27, 23, 1), numpy.uint8
2568
    )
2569
    data[:] = 199
2570
    data[7:9, 11:13] = 13
2571
    data[22:25, 19:22] = 11
2572

2573
    def tiles():
2574
        yield data[:16, :16]
2575
        yield data[:16, 16:]
2576
        yield data[16:, :16]
2577
        yield data[16:, 16:]
2578

2579
    with TempFileName(
2580
        f'issue_tile_generator_{compression}_{predictor}_{samples}'
2581
    ) as fname:
2582
        imwrite(
2583
            fname,
2584
            data=tiles(),
2585
            shape=(27, 23, samples) if samples > 1 else (27, 23),
2586
            dtype=numpy.uint8,
2587
            tile=(16, 16),
2588
            compression=compression,
2589
            predictor=predictor,
2590
        )
2591
        assert_array_equal(imread(fname), data.squeeze())
2592
        if (
2593
            imagecodecs is None
2594
            or not imagecodecs.TIFF.available
2595
            or (compression == 'packbits' and predictor == 'horizontal')
2596
        ):
2597
            return
2598
        assert_array_equal(imagecodecs.imread(fname), data.squeeze())
2599

2600

2601
def test_issue_extratags_filter(caplog):
2602
    """Test filtering extratags."""
2603
    # https://github.com/cgohlke/tifffile/pull/188
2604
    with TempFileName('issue_extratags_filter') as fname:
2605
        imwrite(
2606
            fname,
2607
            shape=(10, 10),
2608
            dtype='u1',
2609
            extratags=[
2610
                (322, 3, 1, 2, False),  # TileWidth is filtered
2611
                (34665, 13, 1, 0, False),  # ExifIFD is filtered
2612
                (270, 2, 0, 'second description', True),  # filtered
2613
                ('FillOrder', 3, 1, 1, True),  # by name should go through
2614
            ],
2615
        )
2616
        assert 'extratag 322' in caplog.text
2617
        assert 'extratag 34665' in caplog.text
2618
        with TiffFile(fname) as tif:
2619
            tags = tif.pages.first.tags
2620
            assert 322 not in tags
2621
            assert 34665 not in tags
2622
            assert tags.get(270, index=1) is None
2623
            assert tags[266].value == 1
2624

2625

2626
@pytest.mark.skipif(
2627
    SKIP_PRIVATE or SKIP_CODECS or not imagecodecs.JPEG.available,
2628
    reason=REASON,
2629
)
2630
def test_issue_invalid_predictor(caplog):
2631
    """Test decoding JPEG compression with invalid predictor tag."""
2632
    fname = private_file('issues/invalid_predictor.tiff')
2633
    with TiffFile(fname) as tif:
2634
        page = tif.pages.first
2635
        assert page.predictor == 58240
2636
        assert page.compression == 7
2637
        data = page.asarray()
2638
        assert 'ignoring predictor' in caplog.text
2639
        assert data.shape == (1275, 1650, 4)
2640

2641

2642
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
2643
def test_issue_ome_missing_frames():
2644
    """Test read OME TIFF with missing pages at end."""
2645
    # https://github.com/cgohlke/tifffile/issues/199
2646
    fname = private_file('issues/stack_t24_y2048_x2448.tiff')
2647
    with TiffFile(fname) as tif:
2648
        assert tif.is_ome
2649
        assert tif.byteorder == '<'
2650
        assert len(tif.pages) == 16
2651
        assert len(tif.series) == 1
2652
        # assert page properties
2653
        page = tif.pages.first
2654
        assert page.photometric == PHOTOMETRIC.MINISBLACK
2655
        assert page.imagewidth == 2448
2656
        assert page.imagelength == 2048
2657
        assert page.bitspersample == 8
2658
        assert not page.is_contiguous
2659
        # assert series properties
2660
        series = tif.series[0]
2661
        assert len(series._pages) == 24
2662
        assert len(series.pages) == 24
2663
        assert series[16] is None
2664
        assert series[23] is None
2665
        assert series.shape == (24, 2048, 2448)
2666
        assert series.dtype == numpy.uint8
2667
        assert series.axes == 'TYX'
2668
        assert series.kind == 'ome'
2669
        data = series.asarray()
2670
        assert_aszarr_method(tif, data)
2671
        assert_aszarr_method(tif, data, chunkmode='page')
2672
        assert__str__(tif)
2673

2674

2675
@pytest.mark.skipif(not IS_WIN, reason=REASON)
2676
def test_issue_maxworkers():
2677
    """Test maxworkers defaults."""
2678
    if 'TIFFFILE_NUM_THREADS' in os.environ:
2679
        assert TIFF.MAXWORKERS == int(os.environ['TIFFFILE_NUM_THREADS'])
2680
    else:
2681
        assert TIFF.MAXWORKERS == max(1, os.cpu_count() // 2)
2682

2683
    if 'TIFFFILE_NUM_IOTHREADS' in os.environ:
2684
        assert TIFF.MAXIOWORKERS == int(os.environ['TIFFFILE_NUM_IOTHREADS'])
2685
    else:
2686
        assert TIFF.MAXIOWORKERS == os.cpu_count() + 4
2687

2688

2689
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
2690
def test_issue_logging_filter(caplog):
2691
    """Test raise an error by filtering logging messages."""
2692
    # https://github.com/cgohlke/tifffile/issues/216
2693
    import logging
2694

2695
    def log_filter(record):
2696
        if record.levelno == logging.ERROR:
2697
            assert record.funcName == '__init__'
2698
            assert 'invalid value offset' in record.msg
2699
            raise ValueError(record.msg)
2700
        return True
2701

2702
    fname = private_file('bad/Gel1.tif')
2703

2704
    logger().addFilter(log_filter)
2705
    try:
2706
        with pytest.raises(ValueError):
2707
            imread(fname)
2708
    finally:
2709
        logger().removeFilter(log_filter)
2710

2711
    assert 'invalid value offset' not in caplog.text
2712
    imread(private_file(fname))
2713
    assert 'invalid value offset' in caplog.text
2714

2715

2716
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
2717
def test_issue_wrong_shape(caplog):
2718
    """Test rewritten file with wrong shape in metadata."""
2719
    # https://github.com/Kitware/UPennContrast/issues/491
2720
    fname = private_file('issues/2023_05_23_pw020_ctrl_well1.tif')
2721
    with TiffFile(fname) as tif:
2722
        assert tif.is_shaped
2723
        page = tif.pages.first
2724
        assert '"shape": [1, 1, 4, 1000, 1000]' in page.description
2725
        assert '"axes": "ZTCYX"' in page.description
2726
        assert page.shape == (1000, 1000, 4)
2727
        series = tif.series[0]
2728
        assert 'shaped series metadata does not match page' in caplog.text
2729
        assert series.shape == (1000, 1000, 4)  # != (1, 1, 4, 1000, 1000)
2730
        assert series.axes == 'YXS'  # != 'ZTCYX'
2731
        assert_array_equal(page.asarray(), series.asarray())
2732

2733

2734
def test_issue_exclusive_creation():
2735
    """Test TiffWriter with exclusive creation mode 'x'."""
2736
    # https://github.com/cgohlke/tifffile/pull/223
2737
    with TempFileName('issue_exclusive_creation') as fname:
2738
        if os.path.exists(fname):
2739
            os.remove(fname)
2740
        with FileHandle(fname, mode='x') as fh:
2741
            assert fh._mode == 'xb'
2742
            with TiffWriter(fh) as tif:
2743
                tif.write(shape=(32, 32), dtype=numpy.uint8)
2744
        with pytest.raises(FileExistsError):
2745
            with FileHandle(fname, mode='x'):
2746
                pass
2747

2748

2749
def test_issue_non_volumetric():
2750
    """Test writing non-volume data with volumetric tile."""
2751
    # https://github.com/cgohlke/tifffile/pull/225
2752
    data = random_data(numpy.uint8, (3, 13, 17))
2753
    with TempFileName('issue_non_volumetric') as fname:
2754
        with pytest.raises(ValueError):
2755
            imwrite(fname, data[0], tile=(3, 16, 16))
2756
        with pytest.raises(ValueError):
2757
            imwrite(fname, data, photometric='rgb', tile=(3, 16, 16))
2758

2759
        # test some other invalid tiles
2760
        with pytest.raises(ValueError):
2761
            imwrite(fname, data, tile=(3, 3, 16, 16), photometric='minisblack')
2762
        with pytest.raises(ValueError):
2763
            imwrite(fname, data, tile=(16,), photometric='minisblack')
2764
        with pytest.raises(ValueError):
2765
            imwrite(fname, data, photometric='rgb', tile=(15, 16))
2766
        with pytest.raises(ValueError):
2767
            imwrite(fname, data, photometric='rgb', tile=(0, 16))
2768

2769
        # test some valid cases
2770
        imwrite(fname, data, tile=(3, 16, 16), photometric='minisblack')
2771
        with TiffFile(fname) as tif:
2772
            page = tif.pages.first
2773
            assert page.is_tiled
2774
            assert page.is_volumetric
2775
            assert page.shape == data.shape
2776

2777
        imwrite(fname, data, photometric='rgb', tile=(1, 16, 16))
2778
        with TiffFile(fname) as tif:
2779
            page = tif.pages.first
2780
            assert page.is_tiled
2781
            assert not page.is_volumetric
2782
            assert page.shape == data.shape
2783

2784
        data = random_data(numpy.uint8, (3, 5, 13, 17))
2785
        imwrite(
2786
            fname,
2787
            data,
2788
            tile=(5, 16, 16),
2789
            photometric='rgb',
2790
            planarconfig='separate',
2791
            metadata=None,
2792
        )
2793
        with TiffFile(fname) as tif:
2794
            assert len(tif.pages) == 1
2795
            page = tif.pages.first
2796
            assert page.is_tiled
2797
            assert page.is_volumetric
2798
            assert page.photometric == PHOTOMETRIC.RGB
2799
            assert page.planarconfig == PLANARCONFIG.SEPARATE
2800
            assert page.shape == data.shape
2801

2802
        data = random_data(numpy.uint8, (5, 13, 17, 3))
2803
        imwrite(
2804
            fname,
2805
            data,
2806
            tile=(5, 16, 16),
2807
            photometric='rgb',
2808
            planarconfig='contig',
2809
            metadata=None,
2810
        )
2811
        with TiffFile(fname) as tif:
2812
            assert len(tif.pages) == 1
2813
            page = tif.pages.first
2814
            assert page.is_tiled
2815
            assert page.is_volumetric
2816
            assert page.photometric == PHOTOMETRIC.RGB
2817
            assert page.planarconfig == PLANARCONFIG.CONTIG
2818
            assert page.shape == data.shape
2819

2820
        data = random_data(numpy.uint8, (5, 13, 17))
2821
        imwrite(
2822
            fname,
2823
            data,
2824
            tile=(16, 16),  # -> (1, 16, 16)
2825
            photometric='miniswhite',
2826
            volumetric=True,
2827
            metadata=None,
2828
        )
2829
        with TiffFile(fname) as tif:
2830
            assert len(tif.pages) == 1
2831
            page = tif.pages.first
2832
            assert page.is_tiled
2833
            assert page.is_volumetric
2834
            assert page.photometric == PHOTOMETRIC.MINISWHITE
2835
            assert page.shape == data.shape
2836

2837

2838
@pytest.mark.skipif(SKIP_ZARR, reason=REASON)
2839
def test_issue_trucated_tileoffsets():
2840
    """Test reading truncated tile offsets and bytecounts."""
2841
    # https://github.com/cgohlke/tifffile/issues/227
2842
    data = random_data(numpy.uint8, (131, 128))
2843
    with TempFileName('issue_trucated_tileoffsets') as fname:
2844
        imwrite(fname, data, tile=(64, 64))
2845
        with TiffFile(fname, mode='r+') as tif:
2846
            # truncate TileOffsets and TileByteCounts
2847
            tag = tif.pages[0].tags[324]
2848
            assert tag.count == 6
2849
            tag.overwrite(tag.value[:4])
2850
            tag = tif.pages[0].tags[325]
2851
            tag.overwrite(tag.value[:4])
2852

2853
        image = imread(fname)
2854
        assert_raises(AssertionError, assert_array_equal, image, data)
2855
        assert_array_equal(image[:128], data[:128])
2856

2857
        store = imread(fname, aszarr=True)
2858
        za = zarr.open(store, mode='r')[:]
2859
        store.close()
2860
        assert_array_equal(za, image)
2861

2862

2863
@pytest.mark.parametrize('buffersize', [0, 1, 1234])
2864
@pytest.mark.parametrize('tile', [0, 1])
2865
def test_issue_buffersize(buffersize, tile):
2866
    """Test reading and writing with custom buffersize."""
2867
    data = random_data(numpy.uint8, (5, 131, 133))
2868
    with TempFileName(f'issue_buffersize_{buffersize}_{tile}') as fname:
2869
        kwargs = {'tile': (32, 32)} if tile else {'rowsperstrip': 8}
2870
        imwrite(
2871
            fname,
2872
            data,
2873
            maxworkers=2,
2874
            buffersize=buffersize,
2875
            compression='zlib',
2876
            **kwargs,
2877
        )
2878
        im = imread(fname, maxworkers=2, buffersize=buffersize)
2879
    assert_array_equal(im, data)
2880

2881

2882
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
2883
def test_issue_ideas(caplog):
2884
    """Test reading invalid TIFF produced by IDEAS."""
2885
    # https://forum.image.sc/t/96103
2886
    # NewSubfileType tag is of type bytes
2887
    # FillOrder tag is zero
2888
    fname = private_file('IDEAS/IDEAS_file.ome.tif')
2889
    with TiffFile(fname) as tif:
2890
        assert '0 is not a valid FILLORDER' in caplog.text
2891
        assert 'invalid self.subfiletype=b' in caplog.text
2892
        assert tif.is_ome
2893
        page = tif.pages.first
2894
        assert page.tags['NewSubfileType'].value == b'\x02\x00'
2895
        assert page.tags['FillOrder'].value == 0
2896
        series = tif.series[0]
2897
        assert series.shape == (37, 29)
2898
        assert series.axes == 'YX'
2899
        assert_array_equal(page.asarray(), series.asarray())
2900

2901

2902
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
2903
def test_issue_nodata_invalid(caplog):
2904
    """Test read GeoTIFF with invalid nodata."""
2905
    fname = private_file('GeoTIFF/nodata_corrupted.tiff')
2906
    with TiffFile(fname) as tif:
2907
        assert 'GDAL_NODATA tag raised ValueError' in caplog.text
2908
        assert tif.byteorder == '<'
2909
        assert len(tif.pages) == 1
2910
        assert len(tif.series) == 1
2911
        assert tif.is_geotiff
2912
        assert tif.is_gdal
2913
        # assert page properties
2914
        page = tif.pages.first
2915
        assert page.dtype == numpy.uint8
2916
        assert page.nodata == 0
2917
        assert page.tags['GDAL_NODATA'].value == '-99999999'
2918
        # assert series properties
2919
        series = tif.series[0]
2920
        assert series.shape == (920, 1300)
2921
        assert series.dtype == numpy.uint8
2922
        assert series.axes == 'YX'
2923
        assert series.kind == 'uniform'
2924
        # assert data
2925
        data = tif.asarray()
2926
        assert isinstance(data, numpy.ndarray)
2927
        assert data[500, 600] == 85
2928
        assert data[0, 0] == 101
2929
        assert_aszarr_method(tif, data)
2930
        del data
2931
        assert__str__(tif)
2932

2933

2934
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
2935
def test_issue_tag_readfunc(caplog):
2936
    """Test allow tag reader functions to fail."""
2937
    # file has an OlympusSIS tag, which is pointing to invalid structure
2938
    fname = private_file('SIS/cirb_NOT_SIS.tif')
2939
    with TiffFile(fname) as tif:
2940
        # assert 'invalid OlympusSIS structure' in caplog.text
2941
        assert tif.pages.first.tags[33560].value == (1382303888,)
2942
        assert 'invalid OlympusSIS structure' in caplog.text
2943
        assert tif.series[0].kind == 'generic'
2944
        data = tif.asarray()
2945
        assert data.shape == (800, 800, 4)
2946
        assert data[166, 290, 2] == 255
2947

2948

2949
@pytest.mark.skipif(
2950
    SKIP_CODECS
2951
    or not imagecodecs.JPEG8.available
2952
    or not imagecodecs.JPEG2K.available
2953
    or not imagecodecs.JPEGXL.available
2954
    or imagecodecs.JPEG8.legacy,
2955
    reason=REASON,
2956
)
2957
def test_issue_jpeg_bitspersample():
2958
    """Test write JPEG with many bitpersample."""
2959
    # https://github.com/cgohlke/tifffile/pull/265
2960

2961
    data6 = random_data(numpy.uint8, (131, 128, 3)) >> 2
2962
    data12 = random_data(numpy.uint16, (131, 128, 3)) >> 4
2963
    jpeg12 = imagecodecs.jpeg_encode(data12, bitspersample=12, lossless=True)
2964

2965
    with TempFileName('issue_jpeg_bitspersample') as fname:
2966
        with TiffWriter(fname) as tif:
2967
            tif.write(
2968
                data6,
2969
                photometric='rgb',
2970
                compression='jpeg',
2971
                compressionargs={'lossless': True},
2972
                bitspersample=6,
2973
            )
2974
            tif.write(
2975
                data12,
2976
                photometric='rgb',
2977
                compression='jpeg',
2978
                compressionargs={'lossless': True, 'bitspersample': 12},
2979
                # bitspersample=12,
2980
            )
2981
            tif.write(
2982
                iter((jpeg12,)),
2983
                shape=data12.shape,
2984
                dtype=data12.dtype,
2985
                photometric='rgb',
2986
                compression='jpeg',
2987
                bitspersample=14,
2988
            )
2989
            tif.write(
2990
                data12,
2991
                photometric='rgb',
2992
                compression='jpeg2000',
2993
                compressionargs={'bitspersample': 12},
2994
            )
2995
            tif.write(
2996
                data12,
2997
                photometric='rgb',
2998
                compression='jpegxl',
2999
                compressionargs={'bitspersample': 12},
3000
            )
3001
            with pytest.raises(ValueError):
3002
                tif.write(
3003
                    data12,
3004
                    photometric='rgb',
3005
                    compression='jpeg',
3006
                    bitspersample=17,
3007
                )
3008
            with pytest.raises(ValueError):
3009
                tif.write(
3010
                    data12,
3011
                    photometric='rgb',
3012
                    compression='jpeg2000',
3013
                    compressionargs={'bitspersample': 0},
3014
                )
3015

3016
        with TiffFile(fname) as tif:
3017
            assert len(tif.pages) == 5
3018
            assert tif.pages[0].bitspersample == 6
3019
            assert tif.pages[1].bitspersample == 12
3020
            assert tif.pages[2].bitspersample == 14
3021
            assert tif.pages[3].bitspersample == 12
3022
            assert tif.pages[4].bitspersample == 12
3023
            assert_array_equal(tif.series[0].asarray(), data6)
3024
            assert_array_equal(tif.series[1].asarray(), data12)
3025
            assert_array_equal(tif.series[2].asarray(), data12)
3026
            assert_array_equal(tif.series[3].asarray(), data12)
3027
            assert_array_equal(tif.series[4].asarray(), data12)
3028

3029
            assert__str__(tif)
3030

3031

3032
def test_issue_ometiff_modulo():
3033
    """Test writing OME-TIFF with modulo dimension."""
3034
    # required for PhasorPy
3035
    data = random_data(numpy.uint8, (3, 3, 31, 33))
3036
    with TempFileName('issue_ometiff_modulo') as fname:
3037
        with TiffWriter(fname, ome=True) as tif:
3038
            tif.write(
3039
                data, photometric='minisblack', metadata={'axes': 'HTYX'}
3040
            )
3041
            tif.write(
3042
                data, photometric='minisblack', metadata={'axes': 'QZYX'}
3043
            )
3044
        with TiffFile(fname) as tif:
3045
            series = tif.series[0]
3046
            assert series.axes == 'HTYX'
3047
            assert series.shape == (3, 3, 31, 33)
3048
            series = tif.series[1]
3049
            assert series.axes == 'QZYX'
3050
            assert series.shape == (3, 3, 31, 33)
3051

3052

3053
def test_issue_ometiff_pixel():
3054
    """Test writing OME-TIFF three one pixel images."""
3055
    # required for PhasorPy
3056
    data = random_data(numpy.uint8, (3, 1, 1))
3057
    with TempFileName('issue_ometiff_pixel') as fname:
3058
        with TiffWriter(fname, ome=True) as tif:
3059
            tif.write(data, photometric='minisblack', metadata={'axes': 'TYX'})
3060
        with TiffFile(fname) as tif:
3061
            series = tif.series[0]
3062
            assert series.axes == 'TYX'
3063
            assert series.shape == (3, 1, 1)
3064

3065

3066
class TestExceptions:
3067
    """Test various Exceptions and Warnings."""
3068

3069
    data = random_data(numpy.uint16, (5, 13, 17))
3070

3071
    @pytest.fixture(scope='class')
3072
    def fname(self):
3073
        with TempFileName('exceptions') as fname:
3074
            yield fname
3075

3076
    def test_nofiles(self):
3077
        # no files found
3078
        with pytest.raises(ValueError):
3079
            imread('*.exceptions')
3080

3081
    def test_memmap(self, fname):
3082
        # not memory-mappable
3083
        imwrite(fname, self.data, compression=8)
3084
        with pytest.raises(ValueError):
3085
            memmap(fname)
3086
        with pytest.raises(ValueError):
3087
            memmap(fname, page=0)
3088

3089
    def test_dimensions(self, fname):
3090
        # dimensions too large
3091
        with pytest.raises(ValueError):
3092
            imwrite(fname, shape=(4294967296, 32), dtype=numpy.uint8)
3093

3094
    def test_no_shape_dtype_empty(self, fname):
3095
        # shape and dtype missing for empty array
3096
        with pytest.raises(ValueError):
3097
            imwrite(fname)
3098

3099
    def test_no_shape_dtype_iter(self, fname):
3100
        # shape and dtype missing for iterator
3101
        with pytest.raises(ValueError):
3102
            imwrite(fname, iter(self.data))
3103

3104
    def test_no_shape_dtype(self, fname):
3105
        # shape and dtype missing
3106
        with TiffWriter(fname) as tif:
3107
            with pytest.raises(ValueError):
3108
                tif.write()
3109

3110
    def test_no_shape(self, fname):
3111
        # shape missing
3112
        with TiffWriter(fname) as tif:
3113
            with pytest.raises(ValueError):
3114
                tif.write(iter(self.data), dtype='u2')
3115

3116
    def test_no_dtype(self, fname):
3117
        # dtype missing
3118
        with TiffWriter(fname) as tif:
3119
            with pytest.raises(ValueError):
3120
                tif.write(iter(self.data), shape=(5, 13, 17))
3121

3122
    def test_mismatch_dtype(self, fname):
3123
        # dtype wrong
3124
        with pytest.raises(ValueError):
3125
            imwrite(fname, self.data, dtype='f4')
3126

3127
    def test_mismatch_shape(self, fname):
3128
        # shape wrong
3129
        with pytest.raises(ValueError):
3130
            imwrite(fname, self.data, shape=(2, 13, 17))
3131

3132
    def test_byteorder(self, fname):
3133
        # invalid byteorder
3134
        with pytest.raises(ValueError):
3135
            imwrite(fname, self.data, byteorder='?')
3136

3137
    def test_truncate_compression(self, fname):
3138
        # truncate cannot be used with compression, packints, or tiles
3139
        with pytest.raises(ValueError):
3140
            imwrite(fname, self.data, compression=8, truncate=True)
3141

3142
    def test_truncate_ome(self, fname):
3143
        # truncate cannot be used with ome-tiff
3144
        with pytest.raises(ValueError):
3145
            imwrite(fname, self.data, ome=True, truncate=True)
3146

3147
    def test_truncate_noshape(self, fname):
3148
        # truncate cannot be used with shaped=False
3149
        with pytest.raises(ValueError):
3150
            imwrite(fname, self.data, shaped=False, truncate=True)
3151

3152
    def test_compression(self, fname):
3153
        # invalid compression
3154
        with pytest.raises(ValueError):
3155
            with pytest.warns(DeprecationWarning):
3156
                imwrite(fname, self.data, compression=(8, None, None, None))
3157

3158
    def test_predictor_dtype(self, fname):
3159
        # cannot apply predictor to dtype complex
3160
        with pytest.raises(ValueError):
3161
            imwrite(
3162
                fname, self.data.astype('F'), predictor=True, compression=8
3163
            )
3164

3165
    def test_predictor_float(self, fname):
3166
        # cannot apply horizontal predictor to float
3167
        with pytest.raises(ValueError):
3168
            imwrite(fname, self.data.astype('f'), predictor=2, compression=8)
3169

3170
    def test_predictor_uint(self, fname):
3171
        # cannot apply float predictor to uint
3172
        with pytest.raises(ValueError):
3173
            imwrite(fname, self.data.astype('H'), predictor=3, compression=8)
3174

3175
    def test_predictor_wrong_compression(self, fname):
3176
        # cannot apply predictor to with image compression schemes
3177
        with pytest.raises(ValueError):
3178
            imwrite(fname, self.data.astype('B'), predictor=2, compression=7)
3179

3180
    def test_predictor_no_compression(self, fname):
3181
        # cannot apply predictor to without compression
3182
        with pytest.raises(ValueError):
3183
            imwrite(fname, self.data.astype('B'), predictor=2, compression=1)
3184

3185
    def test_ome_imagedepth(self, fname):
3186
        # OME-TIFF does not support ImageDepth
3187
        with pytest.raises(ValueError):
3188
            imwrite(fname, self.data, ome=True, volumetric=True)
3189

3190
    def test_imagej_dtype(self, fname):
3191
        # ImageJ does not support dtype
3192
        with pytest.raises(ValueError):
3193
            imwrite(fname, self.data.astype('f8'), imagej=True)
3194

3195
    def test_imagej_imagedepth(self, fname):
3196
        # ImageJ does not support ImageDepth
3197
        with pytest.raises(ValueError):
3198
            imwrite(fname, self.data, imagej=True, volumetric=True)
3199

3200
    def test_imagej_float_rgb(self, fname):
3201
        # ImageJ does not support float with rgb
3202
        with pytest.raises(ValueError):
3203
            imwrite(
3204
                fname,
3205
                self.data[..., :3].astype('f4'),
3206
                imagej=True,
3207
                photometric='rgb',
3208
            )
3209

3210
    def test_imagej_planar(self, fname):
3211
        # ImageJ does not support planar
3212
        with pytest.raises(ValueError):
3213
            imwrite(fname, self.data, imagej=True, planarconfig='separate')
3214

3215
    def test_colormap_shape(self, fname):
3216
        # invalid colormap shape
3217
        with pytest.raises(ValueError):
3218
            imwrite(
3219
                fname,
3220
                self.data.astype('u1'),
3221
                photometric='palette',
3222
                colormap=numpy.empty((3, 254), 'u2'),
3223
            )
3224

3225
    def test_colormap_dtype(self, fname):
3226
        # invalid colormap dtype
3227
        with pytest.raises(ValueError):
3228
            imwrite(
3229
                fname,
3230
                self.data.astype('u1'),
3231
                photometric='palette',
3232
                colormap=numpy.empty((3, 255), 'i2'),
3233
            )
3234

3235
    def test_palette_dtype(self, fname):
3236
        # invalid dtype for palette mode
3237
        with pytest.raises(ValueError):
3238
            imwrite(
3239
                fname,
3240
                self.data.astype('u4'),
3241
                photometric='palette',
3242
                colormap=numpy.empty((3, 255), 'u2'),
3243
            )
3244

3245
    def test_cfa_shape(self, fname):
3246
        # invalid shape for CFA
3247
        with pytest.raises(ValueError):
3248
            imwrite(fname, self.data, photometric='cfa')
3249

3250
    def test_subfiletype_mask(self, fname):
3251
        # invalid SubfileType MASK
3252
        with pytest.raises(ValueError):
3253
            imwrite(fname, self.data, subfiletype=0b100)
3254

3255
    def test_bitspersample_bilevel(self, fname):
3256
        # invalid bitspersample for bilevel
3257
        with pytest.raises(ValueError):
3258
            imwrite(fname, self.data.astype('?'), bitspersample=2)
3259

3260
    def test_bitspersample_jpeg(self, fname):
3261
        # invalid bitspersample for jpeg
3262
        with pytest.raises(ValueError):
3263
            imwrite(fname, self.data, compression='jpeg', bitspersample=17)
3264

3265
    def test_datetime(self, fname):
3266
        # invalid datetime
3267
        with pytest.raises(ValueError):
3268
            imwrite(fname, self.data, datetime='date')
3269

3270
    def test_rgb(self, fname):
3271
        # not a RGB image
3272
        with pytest.raises(ValueError):
3273
            imwrite(fname, self.data[:2], photometric='rgb')
3274

3275
    def test_extrasamples(self, fname):
3276
        # invalid extrasamples
3277
        with pytest.raises(ValueError):
3278
            imwrite(
3279
                fname, self.data, photometric='rgb', extrasamples=(0, 1, 2)
3280
            )
3281

3282
    def test_subsampling(self, fname):
3283
        # invalid subsampling
3284
        with pytest.raises(ValueError):
3285
            imwrite(
3286
                fname,
3287
                self.data[..., :3],
3288
                photometric='rgb',
3289
                compression=7,
3290
                subsampling=(3, 3),
3291
            )
3292

3293
    def test_compress_bilevel(self, fname):
3294
        # cannot compress bilevel image
3295
        with pytest.raises(NotImplementedError):
3296
            imwrite(fname, self.data.astype('?'), compression='jpeg')
3297

3298
    def test_description_unicode(self, fname):
3299
        # strings must be 7-bit ASCII
3300
        with pytest.raises(ValueError):
3301
            imwrite(fname, self.data, description='mu: \u03BC')
3302

3303
    def test_compression_contiguous(self, fname):
3304
        # contiguous cannot be used with compression, tiles
3305
        with TiffWriter(fname) as tif:
3306
            tif.write(self.data[0])
3307
            with pytest.raises(ValueError):
3308
                tif.write(self.data[1], contiguous=True, compression=8)
3309

3310
    def test_imagej_contiguous(self, fname):
3311
        # ImageJ format does not support non-contiguous series
3312
        with TiffWriter(fname, imagej=True) as tif:
3313
            tif.write(self.data[0])
3314
            with pytest.raises(ValueError):
3315
                tif.write(self.data[1], contiguous=False)
3316

3317
    def test_subifds_subifds(self, fname):
3318
        # SubIFDs in SubIFDs are not supported
3319
        with TiffWriter(fname) as tif:
3320
            tif.write(self.data[0], subifds=1)
3321
            with pytest.raises(ValueError):
3322
                tif.write(self.data[1], subifds=1)
3323

3324
    def test_subifds_truncate(self, fname):
3325
        # SubIFDs cannot be used with truncate
3326
        with TiffWriter(fname) as tif:
3327
            tif.write(self.data, subifds=1, truncate=True)
3328
            with pytest.raises(ValueError):
3329
                tif.write(self.data[:, ::2, ::2])
3330

3331
    def test_subifds_imwrite(self, fname):
3332
        # imwrite cannot be used to write SubIFDs
3333
        with pytest.raises(TypeError):
3334
            imwrite(fname, self.data, subifds=1)
3335

3336
    def test_iter_bytes(self, fname):
3337
        # iterator contains wrong number of bytes
3338
        with TiffWriter(fname) as tif:
3339
            with pytest.raises(ValueError):
3340
                tif.write(
3341
                    iter([b'abc']),
3342
                    shape=(13, 17),
3343
                    dtype=numpy.uint8,
3344
                    rowsperstrip=13,
3345
                )
3346

3347
    def test_iter_dtype(self, fname):
3348
        # iterator contains wrong dtype
3349
        with TiffWriter(fname) as tif:
3350
            with pytest.raises(ValueError):
3351
                tif.write(
3352
                    iter(self.data),
3353
                    shape=(5, 13, 17),
3354
                    dtype=numpy.uint8,
3355
                    rowsperstrip=13,
3356
                )
3357

3358
        with TiffWriter(fname) as tif:
3359
            with pytest.raises(ValueError):
3360
                tif.write(
3361
                    iter(self.data),
3362
                    shape=(5, 13, 17),
3363
                    dtype=numpy.uint8,
3364
                    rowsperstrip=5,
3365
                    compression=8,
3366
                )
3367

3368
    def test_tiff_enums(self):
3369
        # TIFF.COMPRESSION and others are deprecated
3370
        with pytest.warns(DeprecationWarning):
3371
            TIFF.COMPRESSION
3372
        with pytest.warns(DeprecationWarning):
3373
            TIFF.EXTRASAMPLE
3374
        with pytest.warns(DeprecationWarning):
3375
            TIFF.FILLORDER
3376
        with pytest.warns(DeprecationWarning):
3377
            TIFF.PHOTOMETRIC
3378
        with pytest.warns(DeprecationWarning):
3379
            TIFF.PLANARCONFIG
3380
        with pytest.warns(DeprecationWarning):
3381
            TIFF.PREDICTOR
3382
        with pytest.warns(DeprecationWarning):
3383
            TIFF.RESUNIT
3384
        with pytest.warns(DeprecationWarning):
3385
            TIFF.RESUNIT
3386

3387
    # def test_extratags(self, fname):
3388
    #     # invalid dtype or count
3389
    #     with pytest.raises(ValueError):
3390
    #         imwrite(fname, data, extratags=[()])
3391

3392
    def test_container_binaryio(self, fname):
3393
        # container cannot be binaryio
3394
        with pytest.raises(ValueError):
3395
            with FileHandle(fname, 'r+') as fh:
3396
                imread(fh, container=fname)
3397

3398
    def test_imagej_colormap(self, fname):
3399
        # invalid colormap shape
3400
        with pytest.raises(ValueError):
3401
            imwrite(
3402
                fname,
3403
                shape=(31, 33),
3404
                dtype=numpy.float32,
3405
                imagej=True,
3406
                colormap=[1, 2, 3],
3407
            )
3408

3409
    def test_photometric(self, fname):
3410
        # not a RGB image
3411
        with pytest.raises(ValueError):
3412
            imwrite(
3413
                fname, shape=(31, 33, 2), dtype=numpy.uint8, photometric='rgb'
3414
            )
3415

3416
    def test_tile(self, fname):
3417
        # invalid tile in iterator
3418
        def tile():
3419
            yield numpy.empty((32, 32), dtype=numpy.uint16)
3420

3421
        with pytest.raises(ValueError):
3422
            imwrite(
3423
                fname,
3424
                tile(),
3425
                shape=(31, 33),
3426
                dtype=numpy.uint16,
3427
                tile=(16, 16),
3428
            )
3429

3430
        with pytest.raises(ValueError):
3431
            imwrite(
3432
                fname, tile(), shape=(31, 33), dtype=numpy.uint8, tile=(32, 32)
3433
            )
3434

3435
    def test_description(self, fname):
3436
        # invalid description type
3437
        with pytest.raises(ValueError):
3438
            imwrite(
3439
                fname,
3440
                shape=(31, 33),
3441
                dtype=numpy.uint8,
3442
                description=32,
3443
                metadata=None,
3444
            )
3445

3446
    def test_omexml(self, fname):
3447
        # invalid OME-XML
3448
        imwrite(fname, shape=(31, 33), dtype=numpy.uint8)
3449
        with pytest.raises(ValueError):
3450
            imread(fname, omexml='OME')
3451

3452
    def test_key(self, fname):
3453
        # invalid key
3454
        imwrite(fname, shape=(31, 33), dtype=numpy.uint8)
3455
        with pytest.raises(TypeError):
3456
            imread(fname, key='1')
3457
        with pytest.raises(TypeError):
3458
            imread(fname, key='1', series=0)
3459

3460
    def test_filemode(self, fname):
3461
        # invalid file open mode
3462
        with pytest.raises(ValueError):
3463
            imread(fname, mode='no')
3464

3465
    @pytest.mark.skipif(
3466
        SKIP_CODECS or not imagecodecs.LERC.available, reason=REASON
3467
    )
3468
    def test_lerc_compression(self, fname):
3469
        # invalid LERC compression
3470
        with pytest.raises(ValueError):
3471
            imwrite(
3472
                fname,
3473
                shape=(31, 33),
3474
                dtype=numpy.uint8,
3475
                compression='LERC',
3476
                compressionargs={'compression': 'jpeg'},
3477
            )
3478

3479
    @pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
3480
    def test_sequence_imread_dtype(self):
3481
        # dtype argument is deprecated
3482
        files = public_file('tifffile/temp_C001T00*.tif')
3483
        with pytest.warns(DeprecationWarning):
3484
            stack = imread(files, dtype=numpy.float64)
3485
        assert_array_equal(stack[0], imread(files[0]))
3486

3487
    @pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
3488
    def test_filesequence_dtype(self):
3489
        # dtype argument is deprecated
3490
        files = public_file('tifffile/temp_C001T00*.tif')
3491
        with pytest.warns(DeprecationWarning):
3492
            TiffSequence(files).asarray(dtype=numpy.float64)
3493
        with pytest.warns(DeprecationWarning):
3494
            TiffSequence(files).asarray(dtype=numpy.float64)
3495
        with pytest.warns(DeprecationWarning):
3496
            TiffSequence(files).aszarr(dtype=numpy.float64)
3497

3498

3499
###############################################################################
3500

3501
# Test specific functions and classes
3502

3503

3504
def test_class_tiffformat():
3505
    """Test TiffFormat class."""
3506
    tiff = TIFF.NDPI_LE
3507
    assert not tiff.is_bigtiff
3508
    assert tiff.is_ndpi
3509
    str(tiff)
3510
    repr(tiff)
3511

3512

3513
def test_class_filecache():
3514
    """Test FileCache class."""
3515
    with TempFileName('class_filecache') as fname:
3516
        cache = FileCache(3)
3517

3518
        with open(fname, 'wb') as fh:
3519
            fh.close()
3520

3521
        # create 6 handles, leaving only first one open
3522
        handles = []
3523
        for i in range(6):
3524
            fh = FileHandle(fname)
3525
            if i > 0:
3526
                fh.close()
3527
            handles.append(fh)
3528

3529
        # open all files
3530
        for fh in handles:
3531
            cache.open(fh)
3532
        assert len(cache) == 6
3533
        for i, fh in enumerate(handles):
3534
            assert not fh.closed
3535
            assert cache.files[fh] == 1 if i else 2
3536

3537
        # close all files: only first file and recently used files are open
3538
        for fh in handles:
3539
            cache.close(fh)
3540
        assert len(cache) == 3
3541
        for i, fh in enumerate(handles):
3542
            assert fh.closed == (0 < i < 4)
3543
            if not 0 < i < 4:
3544
                assert cache.files[fh] == 0 if i else 1
3545

3546
        # open all files, then clear cache: only first file is open
3547
        for fh in handles:
3548
            cache.open(fh)
3549
        cache.clear()
3550
        assert len(cache) == 1
3551
        assert handles[0] in cache.files
3552
        for i, fh in enumerate(handles):
3553
            assert fh.closed == (i > 0)
3554

3555
        # randomly open and close files
3556
        for i in range(13):
3557
            fh = handles[random.randint(0, 5)]
3558
            cache.open(fh)
3559
            cache.close(fh)
3560
            assert len(cache) <= 3
3561
            assert fh in cache.files
3562
            assert handles[0] in cache.files
3563

3564
        # randomly read from files
3565
        for i in range(13):
3566
            fh = handles[random.randint(0, 5)]
3567
            cache.read(fh, 0, 0)
3568
            assert len(cache) <= 3
3569
            assert fh in cache.files
3570
            assert handles[0] in cache.files
3571

3572
        # clear cache: only first file is open
3573
        cache.clear()
3574
        assert len(cache) == 1
3575
        assert handles[0] in cache.files
3576
        for i, fh in enumerate(handles):
3577
            assert fh.closed == (i > 0)
3578

3579
        # open and close all files twice
3580
        for fh in handles:
3581
            cache.open(fh)
3582
            cache.open(fh)
3583
        assert len(cache) == 6
3584
        for i, fh in enumerate(handles):
3585
            assert not fh.closed
3586
            assert cache.files[fh] == 2 if i else 3
3587
        # close files once
3588
        for fh in handles:
3589
            cache.close(fh)
3590
        assert len(cache) == 6
3591
        for i, fh in enumerate(handles):
3592
            assert not fh.closed
3593
            assert cache.files[fh] == 1 if i else 2
3594
        # close files twice
3595
        for fh in handles:
3596
            cache.close(fh)
3597
        assert len(cache) == 3
3598
        for i, fh in enumerate(handles):
3599
            assert fh.closed == (0 < i < 4)
3600
            if not 0 < i < 4:
3601
                assert cache.files[fh] == 0 if i else 1
3602

3603
        # close all files
3604
        cache.clear()
3605
        handles[0].close()
3606

3607

3608
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
3609
def test_class_tifftag_astuple():
3610
    """Test TiffTag.astuple method."""
3611
    fname = private_file('imagej/IJMetadata.tif')
3612
    with TiffFile(fname) as tif:
3613
        tags = tif.pages.first.tags
3614
        assert tags['BitsPerSample'].astuple() == (
3615
            258,
3616
            3,
3617
            1,
3618
            b'\x00\x08',
3619
            True,
3620
        )
3621
        assert tags['ImageDescription'].astuple() == (
3622
            270,
3623
            2,
3624
            60,
3625
            b'ImageJ=1.52b\nimages=3\nchannels=3\nmode=composite\nloop=false'
3626
            b'\x00\x00',
3627
            True,
3628
        )
3629
        assert tags['IJMetadataByteCounts'].astuple() == (
3630
            50838,
3631
            4,
3632
            12,
3633
            b'\x00\x00\x004\x00\x00\x07\xa8\x00\x00\x00\x06\x00\x00\x00\n\x00'
3634
            b'\x00\x00\x08\x00\x00\x000\x00\x00\x03\x00\x00\x00\x03\x00\x00'
3635
            b'\x00\x03\x00\x00\x00\x04\xa4\x00\x00\x00\xc0\x00\x00\x00\x80',
3636
            True,
3637
        )
3638
        assert tags['IJMetadata'].astuple()[:3] == (50839, 1, 5896)
3639

3640

3641
@pytest.mark.parametrize('bigtiff', [False, True])
3642
@pytest.mark.parametrize('byteorder', ['<', '>'])
3643
def test_class_tifftag_overwrite(bigtiff, byteorder):
3644
    """Test TiffTag.overwrite method."""
3645
    data = numpy.ones((16, 16, 3), dtype=byteorder + 'i2')
3646
    bt = '_bigtiff' if bigtiff else ''
3647
    bo = 'be' if byteorder == '>' else 'le'
3648

3649
    with TempFileName(f'class_tifftag_overwrite_{bo}{bt}') as fname:
3650
        imwrite(
3651
            fname,
3652
            data,
3653
            bigtiff=bigtiff,
3654
            photometric=PHOTOMETRIC.RGB,
3655
            software='in',
3656
        )
3657

3658
        with TiffFile(fname, mode='r+') as tif:
3659
            tags = tif.pages.first.tags
3660
            # inline -> inline
3661
            tag = tags[305]
3662
            t305 = tag.overwrite('inl')
3663
            assert tag.valueoffset == t305.valueoffset
3664
            valueoffset = tag.valueoffset
3665
            # xresolution
3666
            tag = tags[282]
3667
            t282 = tag.overwrite((2000, 1000))
3668
            assert tag.valueoffset == t282.valueoffset
3669
            # sampleformat, int -> uint
3670
            tag = tags[339]
3671
            t339 = tags[339].overwrite((1, 1, 1))
3672
            assert tag.valueoffset == t339.valueoffset
3673

3674
        with TiffFile(fname) as tif:
3675
            tags = tif.pages.first.tags
3676
            tag = tags[305]
3677
            assert tag.value == 'inl'
3678
            assert tag.count == t305.count
3679
            tag = tags[282]
3680
            assert tag.value == (2000, 1000)
3681
            assert tag.count == t282.count
3682
            tag = tags[339]
3683
            assert tag.value == (1, 1, 1)
3684
            assert tag.count == t339.count
3685

3686
        # use bytes, specify dtype
3687
        with TiffFile(fname, mode='r+') as tif:
3688
            tags = tif.pages.first.tags
3689
            # xresolution
3690
            tag = tags[282]
3691
            fmt = byteorder + '2I'
3692
            t282 = tag.overwrite(struct.pack(fmt, 2500, 1500), dtype=fmt)
3693
            assert tag.valueoffset == t282.valueoffset
3694

3695
        with TiffFile(fname) as tif:
3696
            tags = tif.pages.first.tags
3697
            tag = tags[282]
3698
            assert tag.value == (2500, 1500)
3699
            assert tag.count == t282.count
3700

3701
        # inline -> separate
3702
        with TiffFile(fname, mode='r+') as tif:
3703
            tag = tif.pages.first.tags[305]
3704
            t305 = tag.overwrite('separate')
3705
            assert tag.valueoffset != t305.valueoffset
3706

3707
        # separate at end -> separate longer
3708
        with TiffFile(fname, mode='r+') as tif:
3709
            tag = tif.pages.first.tags[305]
3710
            assert tag.value == 'separate'
3711
            assert tag.valueoffset == t305.valueoffset
3712
            t305 = tag.overwrite('separate longer')
3713
            assert tag.valueoffset == t305.valueoffset  # overwrite, not append
3714

3715
        # separate -> separate shorter
3716
        with TiffFile(fname, mode='r+') as tif:
3717
            tag = tif.pages.first.tags[305]
3718
            assert tag.value == 'separate longer'
3719
            assert tag.valueoffset == t305.valueoffset
3720
            t305 = tag.overwrite('separate short')
3721
            assert tag.valueoffset == t305.valueoffset
3722

3723
        # separate -> separate longer
3724
        with TiffFile(fname, mode='r+') as tif:
3725
            tag = tif.pages.first.tags[305]
3726
            assert tag.value == 'separate short'
3727
            assert tag.valueoffset == t305.valueoffset
3728
            filesize = tif.filehandle.size
3729
            t305 = tag.overwrite('separate longer')
3730
            assert tag.valueoffset != t305.valueoffset
3731
            assert t305.valueoffset == filesize  # append to end
3732

3733
        # separate -> inline
3734
        with TiffFile(fname, mode='r+') as tif:
3735
            tag = tif.pages.first.tags[305]
3736
            assert tag.value == 'separate longer'
3737
            assert tag.valueoffset == t305.valueoffset
3738
            t305 = tag.overwrite('inl')
3739
            assert tag.valueoffset != t305.valueoffset
3740
            assert t305.valueoffset == valueoffset
3741

3742
        # inline - > erase
3743
        with TiffFile(fname, mode='r+') as tif:
3744
            tag = tif.pages.first.tags[305]
3745
            assert tag.value == 'inl'
3746
            assert tag.valueoffset == t305.valueoffset
3747
            with pytest.raises(TypeError):
3748
                t305 = tag.overwrite(tif, '')
3749
            t305 = tag.overwrite('')
3750
            assert tag.valueoffset == t305.valueoffset
3751

3752
        with TiffFile(fname) as tif:
3753
            tag = tif.pages.first.tags[305]
3754
            assert tag.value == ''
3755
            assert tag.valueoffset == t305.valueoffset
3756

3757
        # change dtype
3758
        with TiffFile(fname, mode='r+') as tif:
3759
            tags = tif.pages.first.tags
3760
            # imagewidth
3761
            tag = tags[256]
3762
            t256 = tag.overwrite(tag.value, dtype=3)
3763
            assert tag.valueoffset == t256.valueoffset
3764

3765
        with TiffFile(fname) as tif:
3766
            tags = tif.pages.first.tags
3767
            tag = tags[256]
3768
            assert tag.value == 16
3769
            assert tag.count == t256.count
3770

3771
        if not bigtiff:
3772
            assert_valid_tiff(fname)
3773

3774

3775
@pytest.mark.skipif(
3776
    SKIP_LARGE
3777
    or SKIP_PRIVATE
3778
    or SKIP_CODECS
3779
    or not imagecodecs.JPEG.available,
3780
    reason=REASON,
3781
)
3782
def test_class_tifftag_overwrite_ndpi():
3783
    """Test TiffTag.overwrite method on 64-bit NDPI file."""
3784
    fname = private_file('HamamatsuNDPI/103680x188160.ndpi')
3785
    with TiffFile(fname, mode='r+') as tif:
3786
        assert tif.is_ndpi
3787
        tags = tif.pages.first.tags
3788

3789
        # inline, old value 32-bit
3790
        assert tags['ImageWidth'].value == 188160
3791
        tags['ImageWidth'].overwrite(0)
3792
        tags['ImageWidth'].overwrite(188160)
3793

3794
        # separate, smaller or same length
3795
        assert tags['Model'].value == 'C13220'
3796
        tags['Model'].overwrite('C13220')
3797

3798
        with pytest.raises(struct.error):
3799
            # new offset > 32-bit
3800
            tags['Model'].overwrite('C13220-')
3801

3802
        assert tags['StripByteCounts'].value == (4461521316,)
3803
        with pytest.raises(ValueError):
3804
            # old value > 32-bit
3805
            tags['StripByteCounts'].overwrite(0)
3806

3807
    with TiffFile(fname, mode='r') as tif:
3808
        assert tif.is_ndpi
3809
        tags = tif.pages.first.tags
3810
        assert tags['ImageWidth'].value == 188160
3811
        assert tags['Model'].value == 'C13220'
3812
        assert tags['StripByteCounts'].value == (4461521316,)
3813

3814

3815
def test_class_tifftags():
3816
    """Test TiffTags interface."""
3817
    data = random_data(numpy.uint8, (21, 31))
3818

3819
    with TempFileName('class_tifftags') as fname:
3820
        imwrite(fname, data, description='test', software=False)
3821

3822
        with TiffFile(fname) as tif:
3823
            tags = tif.pages.first.tags
3824
            # assert len(tags) == 14
3825
            assert 270 in tags
3826
            assert 'ImageDescription' in tags
3827
            assert tags[270].value == 'test'
3828
            assert tags['ImageDescription'].value == 'test'
3829
            assert tags.get(270).value == 'test'
3830
            assert tags.get('ImageDescription').value == 'test'
3831
            assert tags.get(270, index=0).value == 'test'
3832
            assert tags.get('ImageDescription', index=0).value == 'test'
3833
            assert tags.get(270, index=1).value.startswith('{')
3834
            assert tags.get('ImageDescription', index=1).value.startswith('{')
3835
            assert tags.get(270, index=2) is None
3836
            assert tags.get('ImageDescription', index=2) is None
3837
            assert tags.getall(270)[0].value == 'test'
3838
            assert tags.getall(270)[1].value.startswith('{')
3839
            assert tags.getall('ImageDescription')[0].value == 'test'
3840
            assert tags.getall('ImageDescription')[1].value.startswith('{')
3841
            assert tags.getall(0, default=1) == 1
3842
            assert tags.getall('0', default=1) == 1
3843
            assert tags.getall(None, default=1) == 1
3844

3845
            assert len(tags.getall(270)) == 2
3846
            assert 305 not in tags
3847
            assert 'Software' not in tags
3848
            assert tags.get(305) is None
3849
            assert tags.get('Software') is None
3850
            with pytest.raises(KeyError):
3851
                tags[305].value
3852
            with pytest.raises(KeyError):
3853
                tags['Software'].value
3854
            assert len(tags.values()) == len(tags.items())
3855
            assert len(tags.keys()) == len(tags.items()) - 1
3856
            assert set(tags.keys()) == {i[0] for i in tags.items()}
3857
            assert list(tags.values()) == [i[1] for i in tags.items()]
3858
            assert list(tags.values()) == list(tags)
3859

3860
            tag270 = tags[270]
3861
            del tags[270]
3862
            assert 270 not in tags
3863
            assert 'ImageDescription' not in tags
3864
            with pytest.raises(KeyError):
3865
                del tags[270]
3866
            with pytest.raises(KeyError):
3867
                del tags['ImageDescription']
3868

3869
            tags.add(tag270)
3870
            assert 270 in tags
3871
            assert 'ImageDescription' in tags
3872
            del tags['ImageDescription']
3873
            assert 270 not in tags
3874
            assert 'ImageDescription' not in tags
3875

3876
            tags[270] = tag270
3877
            assert 270 in tags
3878
            assert 'ImageDescription' in tags
3879

3880
            assert 0 not in tags
3881
            assert 'None' not in tags
3882
            assert None not in tags
3883
            assert 'TiffTags' in repr(tags)
3884

3885

3886
def test_class_tifftagregistry():
3887
    """Test TiffTagRegistry."""
3888
    numtags = 666
3889
    tags = TIFF.TAGS
3890
    assert len(tags) == numtags
3891
    assert tags[11] == 'ProcessingSoftware'
3892
    assert tags['ProcessingSoftware'] == 11
3893
    assert tags.getall(11) == ['ProcessingSoftware']
3894
    assert tags.getall('ProcessingSoftware') == [11]
3895
    tags.add(11, 'ProcessingSoftware')
3896
    assert len(tags) == numtags
3897

3898
    # one code with two names
3899
    assert 34853 in tags
3900
    assert 'GPSTag' in tags
3901
    assert 'OlympusSIS2' in tags
3902
    assert tags[34853] == 'GPSTag'
3903
    assert tags['GPSTag'] == 34853
3904
    assert tags['OlympusSIS2'] == 34853
3905
    assert tags.getall(34853) == ['GPSTag', 'OlympusSIS2']
3906
    assert tags.getall('GPSTag') == [34853]
3907

3908
    del tags[34853]
3909
    assert len(tags) == numtags - 2
3910
    assert 34853 not in tags
3911
    assert 'GPSTag' not in tags
3912
    assert 'OlympusSIS2' not in tags
3913
    tags.add(34853, 'GPSTag')
3914
    tags.add(34853, 'OlympusSIS2')
3915
    assert 34853 in tags
3916
    assert 'GPSTag' in tags
3917
    assert 'OlympusSIS2' in tags
3918

3919
    info = str(tags)
3920
    assert "34853, 'GPSTag'" in info
3921
    assert "34853, 'OlympusSIS2'" in info
3922

3923
    # two codes with same name
3924
    assert 37387 in tags
3925
    assert 41483 in tags
3926
    assert 'FlashEnergy' in tags
3927
    assert tags[37387] == 'FlashEnergy'
3928
    assert tags[41483] == 'FlashEnergy'
3929
    assert tags['FlashEnergy'] == 37387
3930
    assert tags.getall('FlashEnergy') == [37387, 41483]
3931
    assert tags.getall(37387) == ['FlashEnergy']
3932
    assert tags.getall(41483) == ['FlashEnergy']
3933

3934
    del tags['FlashEnergy']
3935
    assert len(tags) == numtags - 2
3936
    assert 37387 not in tags
3937
    assert 41483 not in tags
3938
    assert 'FlashEnergy' not in tags
3939
    tags.add(37387, 'FlashEnergy')
3940
    tags.add(41483, 'FlashEnergy')
3941
    assert 37387 in tags
3942
    assert 41483 in tags
3943
    assert 'FlashEnergy' in tags
3944

3945
    assert "37387, 'FlashEnergy'" in info
3946
    assert "41483, 'FlashEnergy'" in info
3947

3948

3949
@pytest.mark.parametrize(
3950
    'shape, storedshape, dtype, axes, error',
3951
    [
3952
        # separate and contig
3953
        ((32, 32), (1, 2, 1, 32, 32, 2), numpy.uint8, None, ValueError),
3954
        # depth
3955
        ((32, 32, 32), (1, 1, 32, 32, 32, 1), numpy.uint8, None, OmeXmlError),
3956
        # dtype
3957
        ((32, 32), (1, 1, 1, 32, 32, 1), numpy.float16, None, OmeXmlError),
3958
        # empty
3959
        ((0, 0), (1, 1, 1, 0, 0, 1), numpy.uint8, None, OmeXmlError),
3960
        # not YX
3961
        ((32, 32), (1, 1, 1, 32, 32, 1), numpy.uint8, 'XZ', OmeXmlError),
3962
        # unknown axis
3963
        ((1, 32, 32), (1, 1, 1, 32, 32, 1), numpy.uint8, 'KYX', OmeXmlError),
3964
        # double axis
3965
        ((1, 32, 32), (1, 1, 1, 32, 32, 1), numpy.uint8, 'YYX', OmeXmlError),
3966
        # more than 5 dimensions
3967
        (
3968
            (1, 1, 1, 5, 32, 32),
3969
            (5, 1, 1, 32, 32, 1),
3970
            numpy.uint8,
3971
            None,
3972
            OmeXmlError,
3973
        ),
3974
        # more than 6 dimensions
3975
        (
3976
            (1, 1, 1, 1, 32, 32, 3),
3977
            (1, 1, 1, 32, 32, 3),
3978
            numpy.uint8,
3979
            None,
3980
            OmeXmlError,
3981
        ),
3982
        # more than 8 dimensions
3983
        (
3984
            (1, 1, 1, 1, 1, 1, 1, 32, 32),
3985
            (1, 1, 1, 32, 32, 1),
3986
            numpy.uint8,
3987
            'ARHETZCYX',
3988
            OmeXmlError,
3989
        ),
3990
        # more than 9 dimensions
3991
        (
3992
            (1, 1, 1, 1, 1, 1, 1, 32, 32, 3),
3993
            (1, 1, 1, 32, 32, 3),
3994
            numpy.uint8,
3995
            'ARHETZCYXS',
3996
            OmeXmlError,
3997
        ),
3998
        # double axis
3999
        ((1, 32, 32), (1, 1, 1, 32, 32, 1), numpy.uint8, 'YYX', OmeXmlError),
4000
        # planecount mismatch
4001
        ((3, 32, 32), (1, 1, 1, 32, 32, 1), numpy.uint8, 'CYX', ValueError),
4002
        # stored shape mismatch
4003
        ((3, 32, 32), (1, 2, 1, 32, 32, 1), numpy.uint8, 'SYX', ValueError),
4004
        ((32, 32, 3), (1, 1, 1, 32, 32, 2), numpy.uint8, 'YXS', ValueError),
4005
        ((3, 32, 32), (1, 3, 1, 31, 31, 1), numpy.uint8, 'SYX', ValueError),
4006
        ((32, 32, 3), (1, 1, 1, 31, 31, 3), numpy.uint8, 'YXS', ValueError),
4007
        ((32, 32), (1, 1, 1, 32, 31, 1), numpy.uint8, None, ValueError),
4008
        # too many modulo dimensions
4009
        (
4010
            (2, 3, 4, 5, 32, 32),
4011
            (60, 1, 1, 32, 32, 1),
4012
            numpy.uint8,
4013
            'RHEQYX',
4014
            OmeXmlError,
4015
        ),
4016
    ],
4017
)
4018
def test_class_omexml_fail(shape, storedshape, dtype, axes, error):
4019
    """Test OmeXml class failures."""
4020
    metadata = {'axes': axes} if axes else {}
4021
    ox = OmeXml()
4022
    with pytest.raises(error):
4023
        ox.addimage(dtype, shape, storedshape, **metadata)
4024

4025

4026
@pytest.mark.parametrize(
4027
    'axes, autoaxes, shape, storedshape, dimorder',
4028
    [
4029
        ('YX', 'YX', (32, 32), (1, 1, 1, 32, 32, 1), 'XYCZT'),
4030
        ('YXS', 'YXS', (32, 32, 1), (1, 1, 1, 32, 32, 1), 'XYCZT'),
4031
        ('SYX', 'SYX', (1, 32, 32), (1, 1, 1, 32, 32, 1), 'XYCZT'),
4032
        ('YXS', 'YXS', (32, 32, 3), (1, 1, 1, 32, 32, 3), 'XYCZT'),
4033
        ('SYX', 'SYX', (3, 32, 32), (1, 3, 1, 32, 32, 1), 'XYCZT'),
4034
        ('CYX', 'CYX', (5, 32, 32), (5, 1, 1, 32, 32, 1), 'XYCZT'),
4035
        ('CYXS', 'CYXS', (5, 32, 32, 1), (5, 1, 1, 32, 32, 1), 'XYCZT'),
4036
        ('CSYX', 'ZCYX', (5, 1, 32, 32), (5, 1, 1, 32, 32, 1), 'XYCZT'),  # !
4037
        ('CYXS', 'CYXS', (5, 32, 32, 3), (5, 1, 1, 32, 32, 3), 'XYCZT'),
4038
        ('CSYX', 'CSYX', (5, 3, 32, 32), (5, 3, 1, 32, 32, 1), 'XYCZT'),
4039
        ('TZCYX', 'TZCYX', (3, 4, 5, 32, 32), (60, 1, 1, 32, 32, 1), 'XYCZT'),
4040
        (
4041
            'TZCYXS',
4042
            'TZCYXS',
4043
            (3, 4, 5, 32, 32, 1),
4044
            (60, 1, 1, 32, 32, 1),
4045
            'XYCZT',
4046
        ),
4047
        (
4048
            'TZCSYX',
4049
            'TZCSYX',
4050
            (3, 4, 5, 1, 32, 32),
4051
            (60, 1, 1, 32, 32, 1),
4052
            'XYCZT',
4053
        ),
4054
        (
4055
            'TZCYXS',
4056
            'TZCYXS',
4057
            (3, 4, 5, 32, 32, 3),
4058
            (60, 1, 1, 32, 32, 3),
4059
            'XYCZT',
4060
        ),
4061
        ('ZTCSYX', '', (3, 4, 5, 3, 32, 32), (60, 3, 1, 32, 32, 1), 'XYCTZ'),
4062
    ],
4063
)
4064
@pytest.mark.parametrize('metadata', ('axes', None))
4065
def test_class_omexml(axes, autoaxes, shape, storedshape, dimorder, metadata):
4066
    """Test OmeXml class."""
4067
    dtype = numpy.uint8
4068
    if not metadata and dimorder != 'XYCZT':
4069
        pytest.xfail('')
4070
    metadata = dict(axes=axes) if metadata else dict()
4071
    omexml = OmeXml()
4072
    omexml.addimage(dtype, shape, storedshape, **metadata)
4073
    if IS_WIN:
4074
        assert '\n  ' in str(omexml)
4075
    omexml = omexml.tostring()
4076
    assert dimorder in omexml
4077
    if metadata:
4078
        autoaxes = axes
4079
    for ax in 'XYCZT':
4080
        if ax in autoaxes:
4081
            size = shape[autoaxes.index(ax)]
4082
        else:
4083
            size = 1
4084
        if ax == 'C':
4085
            size *= storedshape[1] * storedshape[-1]
4086
        assert f'Size{ax}="{size}"' in omexml
4087
    assert__repr__(omexml)
4088
    assert_valid_omexml(omexml)
4089

4090

4091
@pytest.mark.parametrize(
4092
    'axes, shape, storedshape, sizetzc, dimorder',
4093
    [
4094
        ('ZAYX', (3, 4, 32, 32), (12, 1, 1, 32, 32, 1), (1, 12, 1), 'XYCZT'),
4095
        ('AYX', (3, 32, 32), (3, 1, 1, 32, 32, 1), (3, 1, 1), 'XYCZT'),
4096
        ('APYX', (3, 4, 32, 32), (12, 1, 1, 32, 32, 1), (3, 4, 1), 'XYCZT'),
4097
        ('TAYX', (3, 4, 32, 32), (12, 1, 1, 32, 32, 1), (12, 1, 1), 'XYCZT'),
4098
        (
4099
            'CHYXS',
4100
            (3, 4, 32, 32, 3),
4101
            (12, 1, 1, 32, 32, 3),
4102
            (1, 1, 36),
4103
            'XYCZT',
4104
        ),
4105
        (
4106
            'CHSYX',
4107
            (3, 4, 3, 32, 32),
4108
            (12, 3, 1, 32, 32, 1),
4109
            (1, 1, 36),
4110
            'XYCZT',
4111
        ),
4112
        (
4113
            'APRYX',
4114
            (3, 4, 5, 32, 32),
4115
            (60, 1, 1, 32, 32, 1),
4116
            (3, 4, 5),
4117
            'XYCZT',
4118
        ),
4119
        (
4120
            'TAPYX',
4121
            (3, 4, 5, 32, 32),
4122
            (60, 1, 1, 32, 32, 1),
4123
            (12, 5, 1),
4124
            'XYCZT',
4125
        ),
4126
        (
4127
            'TZAYX',
4128
            (3, 4, 5, 32, 32),
4129
            (60, 1, 1, 32, 32, 1),
4130
            (3, 20, 1),
4131
            'XYCZT',
4132
        ),
4133
        (
4134
            'ZCHYX',
4135
            (3, 4, 5, 32, 32),
4136
            (60, 1, 1, 32, 32, 1),
4137
            (1, 3, 20),
4138
            'XYCZT',
4139
        ),
4140
        (
4141
            'EPYX',
4142
            (10, 5, 200, 200),
4143
            (50, 1, 1, 200, 200, 1),
4144
            (10, 5, 1),
4145
            'XYCZT',
4146
        ),
4147
        (
4148
            'TQCPZRYX',
4149
            (2, 3, 4, 5, 6, 7, 32, 32),
4150
            (5040, 1, 1, 32, 32, 1),
4151
            (6, 42, 20),
4152
            'XYZCT',
4153
        ),
4154
    ],
4155
)
4156
def test_class_omexml_modulo(axes, shape, storedshape, sizetzc, dimorder):
4157
    """Test OmeXml class with modulo dimensions."""
4158
    dtype = numpy.uint8
4159
    omexml = OmeXml()
4160
    omexml.addimage(dtype, shape, storedshape, axes=axes)
4161
    assert '\n  ' in str(omexml)
4162
    omexml = omexml.tostring()
4163
    assert dimorder in omexml
4164
    for ax, size in zip('TZC', sizetzc):
4165
        assert f'Size{ax}="{size}"' in omexml
4166
    assert__repr__(omexml)
4167
    assert_valid_omexml(omexml)
4168

4169

4170
def test_class_omexml_attributes():
4171
    """Test OmeXml class with attributes and elements."""
4172
    from uuid import uuid1
4173

4174
    uuid = str(uuid1())
4175
    metadata = dict(
4176
        # document
4177
        UUID=uuid,
4178
        Creator=f'test_tifffile.py {tifffile.__version__}',
4179
        # image
4180
        axes='QZYXS',
4181
        Name='ImageName',
4182
        Acquisitiondate='2011-09-16T10:45:48',
4183
        Description='Image "Description" < & >\n{test}',
4184
        TypeDescription={'Q': 'Phasor'},
4185
        SignificantBits=12,
4186
        PhysicalSizeX=1.1,
4187
        PhysicalSizeXUnit='nm',
4188
        PhysicalSizeY=1.2,
4189
        PhysicalSizeYUnit='\xb5m',
4190
        PhysicalSizeZ=1.3,
4191
        PhysicalSizeZUnit='\xc5',
4192
        TimeIncrement=1.4,
4193
        TimeIncrementUnit='\xb5s',
4194
        Channel=dict(Name='ChannelName'),  # one channel with 3 samples
4195
        Plane=dict(PositionZ=[0.0, 0.0, 2.0, 2.0, 4.0, 4.0]),  # 6 TZ-planes
4196
        CommentAnnotation='Tifffile test',
4197
        BooleanAnnotation=True,
4198
        LongAnnotation=[1, 2],
4199
        DoubleAnnotation={'Description': 'A double', 'Value': 1.0},
4200
        MapAnnotation=[
4201
            {'Description': 'description', 'key': '<str/>', 'key2': 1.0},
4202
            {'Namespace': 'ns.org', 'key2': 1, 'key3': 2},
4203
        ],
4204
    )
4205

4206
    omexml = OmeXml(**metadata)
4207
    omexml.addimage(
4208
        numpy.uint16, (2, 3, 32, 32, 3), (6, 1, 1, 32, 32, 3), **metadata
4209
    )
4210
    xml = omexml.tostring()
4211
    for value in (
4212
        f'UUID="urn:uuid:{uuid}"',
4213
        'SizeX="32" SizeY="32" SizeC="3" SizeZ="3" SizeT="2"',
4214
        'Interleaved="true" SignificantBits="12"',
4215
        '<Channel ID="Channel:0:0" SamplesPerPixel="3" Name="ChannelName">',
4216
        '<Plane TheC="0" TheZ="2" TheT="1" PositionZ="4.0"/>',
4217
        '<StructuredAnnotations><XMLAnnotation ID="Annotation:0" Namespace',
4218
        '<ModuloAlongT Type="other" TypeDescription="Phasor" '
4219
        'Start="0" End="1"/>',
4220
        '<CommentAnnotation ID="Annotation:1">'
4221
        '<Value>Tifffile test</Value></CommentAnnotation>',
4222
        '<BooleanAnnotation ID="Annotation:2">'
4223
        '<Value>true</Value></BooleanAnnotation>',
4224
        '<LongAnnotation ID="Annotation:3"><Value>1</Value></LongAnnotation>'
4225
        '<LongAnnotation ID="Annotation:4"><Value>2</Value>',
4226
        '<DoubleAnnotation ID="Annotation:5">'
4227
        '<Description>A double</Description>'
4228
        '<Value>1.0</Value></DoubleAnnotation>',
4229
        '<MapAnnotation ID="Annotation:6">'
4230
        '<Description>description</Description>'
4231
        '<Value><M K="key">&lt;str/&gt;</M><M K="key2">1.0</M></Value>'
4232
        '</MapAnnotation>',
4233
        '<MapAnnotation ID="Annotation:7" Namespace="ns.org">'
4234
        '<Value><M K="key2">1</M><M K="key3">2</M></Value></MapAnnotation>',
4235
    ):
4236
        assert value in xml
4237
    if IS_PYPY:
4238
        pytest.xfail('lxml bug?')
4239
    assert__repr__(omexml)
4240
    assert_valid_omexml(xml)
4241
    assert '\n  ' in str(omexml)
4242

4243
    with TempFileName('class_omexml_attributes') as fname:
4244
        imwrite(
4245
            fname,
4246
            shape=(2, 3, 32, 32, 3),
4247
            dtype=numpy.uint16,
4248
            ome=True,
4249
            photometric='rgb',
4250
            metadata=metadata,
4251
        )
4252
        assert imread(fname).shape == (2, 3, 32, 32, 3)
4253

4254

4255
def test_class_omexml_datasets():
4256
    """Test OmeXml class with datasets."""
4257
    args = numpy.uint8, (3, 7), (1, 1, 1, 3, 7, 1)
4258
    kwargs = {'dtype': numpy.uint8, 'shape': (3, 7)}
4259

4260
    omexml = OmeXml()
4261
    # no dataset
4262
    omexml.addimage(*args, CommentAnnotation='0')
4263
    # first dataset explicit
4264
    omexml.addimage(
4265
        *args,
4266
        Dataset={
4267
            'Name': 'First',
4268
            'Description': 'Dataset',
4269
            'CommentAnnotation': '1',
4270
        },
4271
    )
4272
    # first dataset implicit
4273
    omexml.addimage(*args, CommentAnnotation='2')
4274
    # no dataset
4275
    omexml.addimage(*args, Dataset=None, CommentAnnotation='3')
4276
    # first dataset implicit
4277
    omexml.addimage(*args, CommentAnnotation='4')
4278
    # second dataset explicit
4279
    omexml.addimage(*args, Dataset={'CommentAnnotation': '5'})
4280

4281
    xml = omexml.tostring()
4282
    for value in (
4283
        '<Dataset ID="Dataset:0" Name="First">'
4284
        '<Description>Dataset</Description>'
4285
        '<ImageRef ID="Image:1"/>'
4286
        '<ImageRef ID="Image:2"/>'
4287
        '<ImageRef ID="Image:4"/>'
4288
        '<AnnotationRef ID="Annotation:1"/>'
4289
        '</Dataset>',
4290
        '<Dataset ID="Dataset:1">'
4291
        '<ImageRef ID="Image:5"/>'
4292
        '<AnnotationRef ID="Annotation:5"/>'
4293
        '</Dataset>',
4294
        '<AnnotationRef ID="Annotation:4"/></Image>'
4295
        '<Image ID="Image:5" Name="Image5">',
4296
    ):
4297
        assert value in xml
4298
    if IS_PYPY:
4299
        pytest.xfail('lxml bug?')
4300
    assert__repr__(omexml)
4301
    assert_valid_omexml(xml)
4302
    assert '\n  ' in str(omexml)
4303

4304
    with TempFileName('class_omexml_datasets') as fname:
4305
        with TiffWriter(fname, ome=True) as tif:
4306
            tif.write(**kwargs, metadata={'CommentAnnotation': '0'})
4307
            tif.write(
4308
                **kwargs,
4309
                metadata={
4310
                    'Dataset': {
4311
                        'Name': 'First',
4312
                        'Description': 'Dataset',
4313
                        'CommentAnnotation': '1',
4314
                    }
4315
                },
4316
            )
4317
            tif.write(**kwargs, metadata={'CommentAnnotation': '2'})
4318
            tif.write(
4319
                **kwargs, metadata={'Dataset': None, 'CommentAnnotation': '3'}
4320
            )
4321
            tif.write(**kwargs, metadata={'CommentAnnotation': '4'})
4322
            tif.write(
4323
                **kwargs, metadata={'Dataset': {'CommentAnnotation': '5'}}
4324
            )
4325

4326
        with TiffFile(fname) as tif:
4327
            assert len(tif.series) == 6
4328

4329

4330
def test_class_omexml_multiimage():
4331
    """Test OmeXml class with multiple images."""
4332
    omexml = OmeXml(description='multiimage')
4333
    omexml.addimage(
4334
        numpy.uint8, (32, 32, 3), (1, 1, 1, 32, 32, 3), name='preview'
4335
    )
4336
    omexml.addimage(
4337
        numpy.float32, (4, 256, 256), (4, 1, 1, 256, 256, 1), name='1'
4338
    )
4339
    omexml.addimage('bool', (256, 256), (1, 1, 1, 256, 256, 1), name='mask')
4340
    assert '\n  ' in str(omexml)
4341
    omexml = omexml.tostring()
4342
    assert 'TiffData IFD="0" PlaneCount="1"' in omexml
4343
    assert 'TiffData IFD="1" PlaneCount="4"' in omexml
4344
    assert 'TiffData IFD="5" PlaneCount="1"' in omexml
4345
    assert_valid_omexml(omexml)
4346

4347

4348
def test_class_timer(capsys):
4349
    """Test Timer class."""
4350
    started = Timer.clock()
4351
    with Timer('test_class_timer', started=started) as timer:
4352
        assert timer.started == started
4353
        captured = capsys.readouterr()
4354
        assert captured.out == 'test_class_timer '
4355
        duration = timer.stop()
4356
        assert timer.duration == duration
4357
        assert timer.stopped == started + duration
4358
        timer.duration = 314159.265359
4359
        assert__repr__(timer)
4360
    captured = capsys.readouterr()
4361
    assert captured.out == '3 days, 15:15:59.265359 s\n'
4362

4363

4364
def test_func_xml2dict():
4365
    """Test xml2dict function."""
4366
    xml = """<?xml version="1.0" ?>
4367
    <root attr="attribute">
4368
        <int>-1</int>
4369
        <ints>-1,2</ints>
4370
        <float>-3.14</float>
4371
        <floats>1.0, -2.0</floats>
4372
        <bool>True</bool>
4373
        <string>Lorem, Ipsum</string>
4374
    </root>
4375
    """
4376
    d = xml2dict(xml)['root']
4377
    assert d['attr'] == 'attribute'
4378
    assert d['int'] == -1
4379
    assert d['ints'] == (-1, 2)
4380
    assert d['float'] == -3.14
4381
    assert d['floats'] == (1.0, -2.0)
4382
    assert d['bool'] is True
4383
    assert d['string'] == 'Lorem, Ipsum'
4384

4385
    d = xml2dict(xml, prefix=('a_', 'b_'), sep='')['root']
4386
    assert d['ints'] == '-1,2'
4387
    assert d['floats'] == '1.0, -2.0'
4388

4389

4390
def test_func_memmap():
4391
    """Test memmap function."""
4392
    with TempFileName('func_memmap_new') as fname:
4393
        # create new file
4394
        im = memmap(
4395
            fname,
4396
            shape=(32, 16),
4397
            dtype=numpy.float32,
4398
            bigtiff=True,
4399
            compression=False,
4400
        )
4401
        im[31, 15] = 1.0
4402
        im.flush()
4403
        assert im.shape == (32, 16)
4404
        assert im.dtype == numpy.float32
4405
        del im
4406
        im = memmap(fname, page=0, mode='r')
4407
        assert im[31, 15] == 1.0
4408
        del im
4409
        im = memmap(fname, series=0, mode='c')
4410
        assert im[31, 15] == 1.0
4411
        del im
4412
        # append to file
4413
        im = memmap(
4414
            fname,
4415
            shape=(3, 64, 64),
4416
            dtype=numpy.uint16,
4417
            append=True,
4418
            photometric=PHOTOMETRIC.MINISBLACK,
4419
        )
4420
        im[2, 63, 63] = 1.0
4421
        im.flush()
4422
        assert im.shape == (3, 64, 64)
4423
        assert im.dtype == numpy.uint16
4424
        del im
4425
        im = memmap(fname, page=3, mode='r')
4426
        assert im[63, 63] == 1
4427
        del im
4428
        im = memmap(fname, series=1, mode='c')
4429
        assert im[2, 63, 63] == 1
4430
        del im
4431
        # can not memory-map compressed array
4432
        with pytest.raises(ValueError):
4433
            memmap(
4434
                fname,
4435
                shape=(16, 16),
4436
                dtype=numpy.float32,
4437
                append=True,
4438
                compression=COMPRESSION.ADOBE_DEFLATE,
4439
            )
4440

4441

4442
@pytest.mark.skipif(IS_BE, reason=REASON)
4443
@pytest.mark.parametrize('byteorder', ['>', '<'])
4444
def test_func_memmap_byteorder(byteorder):
4445
    """Test non-native byteorder can be memory mapped."""
4446
    bo = {'<': 'le', '>': 'be'}[byteorder]
4447

4448
    with TempFileName(f'func_memmap_byteorder_{bo}') as fname:
4449
        if os.path.exists(fname):
4450
            os.remove(fname)
4451

4452
        # new, empty file
4453
        im = memmap(
4454
            fname, shape=(16, 16), dtype=numpy.uint16, byteorder=byteorder
4455
        )
4456
        assert im.dtype.byteorder == byteorder
4457
        im[0, 0] = 253
4458
        im[1, 1] = 257
4459
        del im
4460

4461
        with TiffFile(fname) as tif:
4462
            assert tif.byteorder == byteorder
4463
            im = tif.asarray()
4464
            assert im.dtype.byteorder in {'<', '='}  # native
4465
            assert im[0, 0] == 253
4466
            assert im[1, 1] == 257
4467

4468
        im = memmap(fname, mode='r')
4469
        assert im.dtype.byteorder == '=' if byteorder == '<' else '>'
4470
        assert im[0, 0] == 253
4471
        assert im[1, 1] == 257
4472
        del im
4473

4474

4475
def test_func_repeat_nd():
4476
    """Test repeat_nd function."""
4477
    a = repeat_nd([[0, 1, 2], [3, 4, 5], [6, 7, 8]], (2, 3))
4478
    assert_array_equal(
4479
        a,
4480
        [
4481
            [0, 0, 0, 1, 1, 1, 2, 2, 2],
4482
            [0, 0, 0, 1, 1, 1, 2, 2, 2],
4483
            [3, 3, 3, 4, 4, 4, 5, 5, 5],
4484
            [3, 3, 3, 4, 4, 4, 5, 5, 5],
4485
            [6, 6, 6, 7, 7, 7, 8, 8, 8],
4486
            [6, 6, 6, 7, 7, 7, 8, 8, 8],
4487
        ],
4488
    )
4489

4490

4491
def test_func_byteorder_isnative():
4492
    """Test byteorder_isnative function."""
4493
    assert byteorder_isnative(sys.byteorder)
4494
    assert byteorder_isnative('=')
4495
    if sys.byteorder == 'little':
4496
        assert byteorder_isnative('<')
4497
        assert not byteorder_isnative('>')
4498
    else:
4499
        assert byteorder_isnative('>')
4500
        assert not byteorder_isnative('<')
4501

4502

4503
def test_func_byteorder_compare():
4504
    """Test byteorder_isnative function."""
4505
    assert byteorder_compare('<', '<')
4506
    assert byteorder_compare('>', '>')
4507
    assert byteorder_compare('=', '=')
4508
    assert byteorder_compare('|', '|')
4509
    assert byteorder_compare('>', '|')
4510
    assert byteorder_compare('<', '|')
4511
    assert byteorder_compare('|', '>')
4512
    assert byteorder_compare('|', '<')
4513
    assert byteorder_compare('=', '|')
4514
    assert byteorder_compare('|', '=')
4515
    if sys.byteorder == 'little':
4516
        assert byteorder_compare('<', '=')
4517
    else:
4518
        assert byteorder_compare('>', '=')
4519

4520

4521
def test_func_reshape_nd():
4522
    """Test reshape_nd function."""
4523
    assert reshape_nd(numpy.empty(0), 2).shape == (1, 0)
4524
    assert reshape_nd(numpy.empty(1), 3).shape == (1, 1, 1)
4525
    assert reshape_nd(numpy.empty((2, 3)), 3).shape == (1, 2, 3)
4526
    assert reshape_nd(numpy.empty((2, 3, 4)), 3).shape == (2, 3, 4)
4527

4528
    assert reshape_nd((0,), 2) == (1, 0)
4529
    assert reshape_nd((1,), 3) == (1, 1, 1)
4530
    assert reshape_nd((2, 3), 3) == (1, 2, 3)
4531
    assert reshape_nd((2, 3, 4), 3) == (2, 3, 4)
4532

4533

4534
def test_func_order_axes():
4535
    axes = [(0, 2, 0), (1, 2, 0), (0, 2, 1), (1, 2, 1)]
4536
    # first axis varies fastest, second axis is constant
4537
    assert order_axes(axes, True) == (2, 0)
4538
    assert order_axes(axes, False) == (1, 2, 0)
4539

4540

4541
def test_func_apply_colormap():
4542
    """Test apply_colormap function."""
4543
    image = numpy.arange(256, dtype=numpy.uint8)
4544
    colormap = numpy.vstack([image, image, image]).astype(numpy.uint16) * 256
4545
    assert_array_equal(apply_colormap(image, colormap)[-1], colormap[:, -1])
4546

4547

4548
def test_func_parse_filenames():
4549
    """Test parse_filenames function."""
4550

4551
    def func(*args, **kwargs):
4552
        labels, shape, indices, _ = parse_filenames(*args, **kwargs)
4553
        return ''.join(labels), shape, indices
4554

4555
    files = ['c1t001.ext', 'c1t002.ext', 'c2t002.ext']  # 'c2t001.ext' missing
4556
    # group names
4557
    p = r'(?P<a>\d).[!\d](?P<b>\d+)\.ext'
4558
    assert func(files[:1], p) == ('ab', (1, 1), [(0, 0)])  # (1, 1)
4559
    assert func(files[:2], p) == ('ab', (1, 2), [(0, 0), (0, 1)])  # (1, 1)
4560
    assert func(files, p) == ('ab', (2, 2), [(0, 0), (0, 1), (1, 1)])  # (1, 1)
4561
    # unknown axes
4562
    p = r'(\d)[^\d](\d+)\.ext'
4563
    assert func(files[:1], p) == ('QQ', (1, 1), [(0, 0)])  # (1, 1)
4564
    assert func(files[:2], p) == ('QQ', (1, 2), [(0, 0), (0, 1)])  # (1, 1)
4565
    assert func(files, p) == ('QQ', (2, 2), [(0, 0), (0, 1), (1, 1)])  # (1, 1)
4566
    # match axes
4567
    p = r'([^\d])(\d)([^\d])(\d+)\.ext'
4568
    assert func(files[:1], p) == ('ct', (1, 1), [(0, 0)])  # (1, 1)
4569
    assert func(files[:2], p) == ('ct', (1, 2), [(0, 0), (0, 1)])  # (1, 1)
4570
    assert func(files, p) == ('ct', (2, 2), [(0, 0), (0, 1), (1, 1)])  # (1, 1)
4571
    # misc
4572
    files = ['c0t001.ext', 'c0t002.ext', 'c2t002.ext']  # 'c2t001.ext' missing
4573
    p = r'([^\d])(\d)[^\d](?P<b>\d+)\.ext'
4574
    assert func(files[:1], p) == ('cb', (1, 1), [(0, 0)])  # (0, 1)
4575
    assert func(files[:2], p) == ('cb', (1, 2), [(0, 0), (0, 1)])  # (0, 1)
4576
    assert func(files, p) == ('cb', (3, 2), [(0, 0), (0, 1), (2, 1)])  # (0, 1)
4577

4578
    # BBBC006_v1
4579
    categories = {'p': {chr(i + 97): i for i in range(25)}}
4580
    files = [
4581
        'BBBC006_v1_images_z_00/mcf-z-stacks-03212011_a01_s1_w1a57.tif',
4582
        'BBBC006_v1_images_z_00/mcf-z-stacks-03212011_a03_s2_w1419.tif',
4583
        'BBBC006_v1_images_z_00/mcf-z-stacks-03212011_p24_s2_w2283.tif',
4584
        'BBBC006_v1_images_z_01/mcf-z-stacks-03212011_p24_s2_w11cf.tif',
4585
    ]
4586
    # don't match directory
4587
    p = r'_(?P<p>[a-z])(?P<a>\d+)(?:_(s)(\d))(?:_(w)(\d))'
4588
    assert func(files[:1], p, categories=categories) == (
4589
        'pasw',
4590
        (1, 1, 1, 1),
4591
        [(0, 0, 0, 0)],
4592
        # (97, 1, 1, 1),
4593
    )
4594
    assert func(files[:2], p, categories=categories) == (
4595
        'pasw',
4596
        (1, 3, 2, 1),
4597
        [(0, 0, 0, 0), (0, 2, 1, 0)],
4598
        # (97, 1, 1, 1),
4599
    )
4600
    # match directory
4601
    p = r'(?:_(z)_(\d+)).*_(?P<p>[a-z])(?P<a>\d+)(?:_(s)(\d))(?:_(w)(\d))'
4602
    assert func(files, p, categories=categories) == (
4603
        'zpasw',
4604
        (2, 16, 24, 2, 2),
4605
        [
4606
            (0, 0, 0, 0, 0),
4607
            (0, 0, 2, 1, 0),
4608
            (0, 15, 23, 1, 1),
4609
            (1, 15, 23, 1, 0),
4610
        ],
4611
        # (0, 97, 1, 1, 1),
4612
    )
4613
    # reorder axes
4614
    p = r'(?:_(z)_(\d+)).*_(?P<p>[a-z])(?P<a>\d+)(?:_(s)(\d))(?:_(w)(\d))'
4615
    assert func(
4616
        files, p, axesorder=(2, 0, 1, 3, 4), categories=categories
4617
    ) == (
4618
        'azpsw',
4619
        (24, 2, 16, 2, 2),
4620
        [
4621
            (0, 0, 0, 0, 0),
4622
            (2, 0, 0, 1, 0),
4623
            (23, 0, 15, 1, 1),
4624
            (23, 1, 15, 1, 0),
4625
        ],
4626
        # (1, 0, 97, 1, 1),
4627
    )
4628

4629

4630
def test_func_reshape_axes():
4631
    """Test reshape_axes function."""
4632
    assert reshape_axes('YXS', (219, 301, 1), (219, 301, 1)) == 'YXS'
4633
    assert reshape_axes('YXS', (219, 301, 3), (219, 301, 3)) == 'YXS'
4634
    assert reshape_axes('YXS', (219, 301, 1), (219, 301)) == 'YX'
4635
    assert reshape_axes('YXS', (219, 301, 1), (219, 1, 1, 301, 1)) == 'YQQXS'
4636
    assert reshape_axes('IYX', (12, 219, 301), (3, 4, 219, 301, 1)) == 'QQYXQ'
4637
    assert (
4638
        reshape_axes('IYX', (12, 219, 301), (3, 4, 219, 1, 301, 1)) == 'QQYQXQ'
4639
    )
4640
    assert (
4641
        reshape_axes('IYX', (12, 219, 301), (3, 2, 219, 2, 301, 1)) == 'QQQQXQ'
4642
    )
4643
    with pytest.raises(ValueError):
4644
        reshape_axes('IYX', (12, 219, 301), (3, 4, 219, 2, 301, 1))
4645
    with pytest.raises(ValueError):
4646
        reshape_axes('IYX', (12, 219, 301), (3, 4, 219, 301, 2))
4647

4648

4649
def test_func_julian_datetime():
4650
    """Test julian_datetime function."""
4651
    assert julian_datetime(2451576, 54362783) == (
4652
        datetime.datetime(2000, 2, 2, 15, 6, 2, 783)
4653
    )
4654

4655

4656
def test_func_excel_datetime():
4657
    """Test excel_datetime function."""
4658
    assert excel_datetime(40237.029999999795) == (
4659
        datetime.datetime(2010, 2, 28, 0, 43, 11, 999982)
4660
    )
4661

4662

4663
def test_func_natural_sorted():
4664
    """Test natural_sorted function."""
4665
    assert natural_sorted(['f1', 'f2', 'f10']) == ['f1', 'f2', 'f10']
4666

4667

4668
def test_func_stripnull():
4669
    """Test stripnull function."""
4670
    assert stripnull(b'string\x00') == b'string'
4671
    assert stripnull('string\x00', null='\0') == 'string'
4672
    assert (
4673
        stripnull(b'string\x00string\x00\x00', first=False)
4674
        == b'string\x00string'
4675
    )
4676
    assert (
4677
        stripnull('string\x00string\x00\x00', null='\0', first=False)
4678
        == 'string\x00string'
4679
    )
4680

4681

4682
def test_func_stripascii():
4683
    """Test stripascii function."""
4684
    assert stripascii(b'string\x00string\n\x01\x00') == b'string\x00string\n'
4685
    assert stripascii(b'\x00') == b''
4686

4687

4688
def test_func_sequence():
4689
    """Test sequence function."""
4690
    assert sequence(1) == (1,)
4691
    assert sequence([1]) == [1]
4692

4693

4694
def test_func_product():
4695
    """Test product function."""
4696
    assert product([2**8, 2**30]) == 274877906944
4697
    assert product([]) == 1
4698
    assert product(numpy.array([2**8, 2**30], numpy.int32)) == 274877906944
4699

4700

4701
def test_func_squeeze_axes():
4702
    """Test squeeze_axes function."""
4703
    assert squeeze_axes((5, 1, 2, 1, 1), 'TZYXC') == (
4704
        (5, 2, 1),
4705
        'TYX',
4706
        (True, False, True, True, False),
4707
    )
4708
    assert squeeze_axes((1,), 'Y') == ((1,), 'Y', (True,))
4709
    assert squeeze_axes((1,), 'Q') == ((1,), 'Q', (True,))
4710
    assert squeeze_axes((1, 1), 'PQ') == ((1,), 'Q', (False, True))
4711

4712

4713
def test_func_transpose_axes():
4714
    """Test transpose_axes function."""
4715
    assert transpose_axes(
4716
        numpy.zeros((2, 3, 4, 5)), 'TYXC', asaxes='CTZYX'
4717
    ).shape == (5, 2, 1, 3, 4)
4718

4719

4720
def test_func_subresolution():
4721
    """Test subresolution function."""
4722

4723
    class a:
4724
        dtype = numpy.uint8
4725
        axes = 'QzyxS'
4726
        shape = (3, 256, 512, 1024, 4)
4727

4728
    class b:
4729
        dtype = numpy.uint8
4730
        axes = 'QzyxS'
4731
        shape = (3, 128, 256, 512, 4)
4732

4733
    assert subresolution(a, a) == 0
4734
    assert subresolution(a, b) == 1
4735
    assert subresolution(a, b, p=2, n=2) == 1
4736
    assert subresolution(a, b, p=3) is None
4737
    b.shape = (3, 86, 171, 342, 4)
4738
    assert subresolution(a, b, p=3) == 1
4739
    b.shape = (3, 128, 256, 512, 2)
4740
    assert subresolution(a, b) is None
4741
    b.shape = (3, 64, 256, 512, 4)
4742
    assert subresolution(a, b) is None
4743
    b.shape = (3, 128, 64, 512, 4)
4744
    assert subresolution(a, b) is None
4745
    b.shape = (3, 128, 256, 1024, 4)
4746
    assert subresolution(a, b) is None
4747
    b.shape = (3, 32, 64, 128, 4)
4748
    assert subresolution(a, b) == 3
4749

4750

4751
@pytest.mark.skipif(IS_BE, reason=REASON)
4752
def test_func_unpack_rgb():
4753
    """Test unpack_rgb function."""
4754
    data = struct.pack('BBBB', 0x21, 0x08, 0xFF, 0xFF)
4755
    assert_array_equal(
4756
        unpack_rgb(data, '<B', (5, 6, 5), False), [1, 1, 1, 31, 63, 31]
4757
    )
4758
    assert_array_equal(
4759
        unpack_rgb(data, '<B', (5, 6, 5)), [8, 4, 8, 255, 255, 255]
4760
    )
4761
    assert_array_equal(
4762
        unpack_rgb(data, '<B', (5, 5, 5)), [16, 8, 8, 255, 255, 255]
4763
    )
4764

4765

4766
def test_func_shaped_description():
4767
    """Test shaped_description function."""
4768
    descr = shaped_description((256, 256, 3), axes='YXS')
4769
    assert json.loads(descr) == {'shape': [256, 256, 3], 'axes': 'YXS'}
4770

4771

4772
def test_func_shaped_description_metadata():
4773
    """Test shaped_description_metadata function."""
4774
    assert shaped_description_metadata('shape=(256, 256, 3)') == {
4775
        'shape': (256, 256, 3)
4776
    }
4777
    assert shaped_description_metadata(
4778
        '{"shape": [256, 256, 3], "axes": "YXS"}'
4779
    ) == {'shape': [256, 256, 3], 'axes': 'YXS'}
4780

4781

4782
def test_func_imagej_shape():
4783
    """Test imagej_shape function."""
4784
    for k, v in (
4785
        ((1, None), (1, 1, 1, 1, 1, 1)),
4786
        ((3, None), (1, 1, 1, 1, 3, 1)),
4787
        ((4, 3, None), (1, 1, 1, 4, 3, 1)),
4788
        ((4, 3, True), (1, 1, 1, 1, 4, 3)),
4789
        ((4, 4, None), (1, 1, 1, 4, 4, 1)),
4790
        ((4, 4, True), (1, 1, 1, 1, 4, 4)),
4791
        ((4, 3, 1, None), (1, 1, 1, 4, 3, 1)),
4792
        ((4, 3, 2, None), (1, 1, 4, 3, 2, 1)),
4793
        ((4, 3, 3, None), (1, 1, 1, 4, 3, 3)),
4794
        ((4, 3, 4, None), (1, 1, 1, 4, 3, 4)),
4795
        ((4, 3, 4, True), (1, 1, 1, 4, 3, 4)),
4796
        ((4, 3, 4, False), (1, 1, 4, 3, 4, 1)),
4797
        ((4, 3, 5, None), (1, 1, 4, 3, 5, 1)),
4798
        ((3, 2, 1, 5, 4, None), (1, 3, 2, 1, 5, 4)),
4799
        ((3, 2, 1, 4, 5, None), (3, 2, 1, 4, 5, 1)),
4800
        ((1, 2, 3, 4, 5, None), (1, 2, 3, 4, 5, 1)),
4801
        ((2, 3, 4, 5, 3, None), (1, 2, 3, 4, 5, 3)),
4802
        ((2, 3, 4, 5, 3, True), (1, 2, 3, 4, 5, 3)),
4803
        ((2, 3, 4, 5, 3, False), (2, 3, 4, 5, 3, 1)),
4804
        ((1, 2, 3, 4, 5, 4, None), (1, 2, 3, 4, 5, 4)),
4805
        ((6, 5, 4, 3, 2, 1, None), (6, 5, 4, 3, 2, 1)),
4806
    ):
4807
        assert imagej_shape(k[:-1], rgb=k[-1]) == v
4808

4809

4810
def test_func_imagej_description():
4811
    """Test imagej_description function."""
4812
    expected = (
4813
        'ImageJ=1.11a\nimages=510\nchannels=2\nslices=5\n'
4814
        'frames=51\nhyperstack=true\nmode=grayscale\nloop=false\n'
4815
    )
4816
    assert imagej_description((51, 5, 2, 196, 171)) == expected
4817
    assert imagej_description((51, 5, 2, 196, 171), axes='TZCYX') == expected
4818
    expected = (
4819
        'ImageJ=1.11a\nimages=2\nslices=2\nhyperstack=true\nmode=grayscale\n'
4820
    )
4821
    assert imagej_description((1, 2, 1, 196, 171)) == expected
4822
    assert imagej_description((2, 196, 171), axes='ZYX') == expected
4823
    expected = 'ImageJ=1.11a\nimages=1\nhyperstack=true\nmode=grayscale\n'
4824
    assert imagej_description((196, 171)) == expected
4825
    assert imagej_description((196, 171), axes='YX') == expected
4826
    expected = 'ImageJ=1.11a\nimages=1\nhyperstack=true\n'
4827
    assert imagej_description((196, 171, 3)) == expected
4828
    assert imagej_description((196, 171, 3), axes='YXS') == expected
4829

4830
    with pytest.raises(ValueError):
4831
        imagej_description((196, 171, 3), axes='TYXS')
4832
    with pytest.raises(ValueError):
4833
        imagej_description((196, 171, 2), axes='TYXS')
4834
    with pytest.raises(ValueError):
4835
        imagej_description((3, 196, 171, 3), axes='ZTYX')
4836

4837

4838
def test_func_imagej_description_metadata():
4839
    """Test imagej_description_metadata function."""
4840
    imagej_str = (
4841
        'ImageJ=1.11a\nimages=510\nchannels=2\nslices=5\n'
4842
        'frames=51\nhyperstack=true\nmode=grayscale\nloop=false\n'
4843
    )
4844
    imagej_dict = {
4845
        'ImageJ': '1.11a',
4846
        'images': 510,
4847
        'channels': 2,
4848
        'slices': 5,
4849
        'frames': 51,
4850
        'hyperstack': True,
4851
        'mode': 'grayscale',
4852
        'loop': False,
4853
    }
4854
    assert imagej_description_metadata(imagej_str) == imagej_dict
4855

4856

4857
def test_func_pilatus_header_metadata():
4858
    """Test pilatus_description_metadata function."""
4859
    header = """
4860
        # Detector: PILATUS 300K, 3-0101
4861
        # 2011-07-22T17:33:22.529
4862
        # Pixel_size 172e-6 m x 172e-6 m
4863
        # Silicon sensor, thickness 0.000320 m
4864
        # Exposure_time 0.0970000 s
4865
        # Exposure_period 0.1000000 s
4866
        # Tau = 383.8e-09 s
4867
        # Count_cutoff 126367 counts
4868
        # Threshold_setting: not set
4869
        # Gain_setting: high gain (vrf = -0.150)
4870
        # N_excluded_pixels = 19
4871
        # Excluded_pixels: badpix_mask.tif
4872
        # Flat_field: (nil)
4873
        # Trim_file: p300k0101_E8048_T4024_vrf_m0p15.bin
4874
        #  Beam_xy (243.12, 309.12) pixels
4875
        # Image_path: /ramdisk/
4876
            Invalid
4877
        # Unknown 1 2 3 4 5""".strip().replace(
4878
        '            ', ''
4879
    )
4880
    attr = pilatus_description_metadata(header)
4881
    assert attr['Detector'] == 'PILATUS 300K 3-0101'
4882
    assert attr['Pixel_size'] == (0.000172, 0.000172)
4883
    assert attr['Silicon'] == 0.000320
4884
    # self.assertEqual(attr['Threshold_setting'], float('nan'))
4885
    assert attr['Beam_xy'] == (243.12, 309.12)
4886
    assert attr['Unknown'] == '1 2 3 4 5'
4887

4888

4889
def test_func_astrotiff_description_metadata(caplog):
4890
    """Test astrotiff_description_metadata function."""
4891
    assert (
4892
        astrotiff_description_metadata(
4893
            """
4894
SIMPLE  =                    T / file does conform to FITS standard
4895
COMMENT 1  First comment.
4896
UNDEF   =                      / undefined
4897
STRING  = 'a string'           / string
4898
STRING1 = ''                   / null string
4899
STRING2 = '    '               / empty string
4900
STRING3 = ' string with / .'   / comment with / . and leading whitespace
4901
STRING4 = 'string longer than  30 characters' / long string
4902
COMMENT 2  Second comment, longer than 30 characters.
4903
COMMENT 3  Third comment with /.
4904
NOCOMMEN=                    1
4905
TRUE    =                    T / True
4906
FALSE   =                    F / False
4907
INT     =                  123 / Integer
4908
FLOAT   =  123.456789123456789 / Float
4909
FLOAT2  =                 123. / Float
4910
FLOAT3  = -123.4564890000E-001 / Scientific
4911
CINT    =            (123, 45) / Complex integer
4912
CFLT    =       (23.23, -45.7) / Complex float
4913
JD      =   2457388.4562152778 / Julian date cannot be represented as float ?
4914
UNIT    =                  123 / [unit] comment
4915
CUSTOM  = '+12 34 56'          / [+dd mm ss] custom unit
4916
DUPLICAT=                    1
4917
DUPLICAT=                    2
4918
INVALID1=                 None / invalid value
4919
INVALID2= '                    / invalid string
4920
END
4921
"""
4922
        )
4923
        == {
4924
            'SIMPLE': True,
4925
            'SIMPLE:COMMENT': 'file does conform to FITS standard',
4926
            'COMMENT:0': '1  First comment.',
4927
            'UNDEF': None,
4928
            'UNDEF:COMMENT': 'undefined',
4929
            'STRING': 'a string',
4930
            'STRING:COMMENT': 'string',
4931
            'STRING1': '',
4932
            'STRING1:COMMENT': 'null string',
4933
            'STRING2': '    ',
4934
            'STRING2:COMMENT': 'empty string',
4935
            'STRING3': ' string with / .',
4936
            'STRING3:COMMENT': 'comment with / . and leading whitespace',
4937
            'STRING4': 'string longer than  30 characters',
4938
            'STRING4:COMMENT': 'long string',
4939
            'COMMENT:1': '2  Second comment, longer than 30 characters.',
4940
            'COMMENT:2': '3  Third comment with /.',
4941
            'NOCOMMEN': 1,
4942
            'TRUE': True,
4943
            'TRUE:COMMENT': 'True',
4944
            'FALSE': False,
4945
            'FALSE:COMMENT': 'False',
4946
            'INT': 123,
4947
            'INT:COMMENT': 'Integer',
4948
            'FLOAT': 123.45678912345679,
4949
            'FLOAT:COMMENT': 'Float',
4950
            'FLOAT2': 123.0,
4951
            'FLOAT2:COMMENT': 'Float',
4952
            'FLOAT3': -12.3456489,
4953
            'FLOAT3:COMMENT': 'Scientific',
4954
            'CINT': (123, 45),
4955
            'CINT:COMMENT': 'Complex integer',
4956
            'CFLT': (23.23, -45.7),
4957
            'CFLT:COMMENT': 'Complex float',
4958
            'JD': 2457388.456215278,
4959
            'JD:COMMENT': 'Julian date cannot be represented as float ?',
4960
            'UNIT': 123,
4961
            'UNIT:COMMENT': '[unit] comment',
4962
            'UNIT:UNIT': 'unit',
4963
            'CUSTOM': '+12 34 56',
4964
            'CUSTOM:COMMENT': '[+dd mm ss] custom unit',
4965
            'CUSTOM:UNIT': '+dd mm ss',
4966
            'DUPLICAT': 2,
4967
            'END:0': '',
4968
        }
4969
    )
4970
    assert 'DUPLICAT: duplicate key' in caplog.text
4971
    assert 'INVALID1: invalid value' in caplog.text
4972
    assert 'INVALID2: invalid string' in caplog.text
4973

4974

4975
def test_func_matlabstr2py():
4976
    """Test matlabstr2py function."""
4977
    assert matlabstr2py('1') == 1
4978
    assert matlabstr2py(
4979
        "['x y z' true false; 1 2.0 -3e4; Inf Inf @class;[1;2;3][1 2] 3]"
4980
    ) == [
4981
        ['x y z', True, False],
4982
        [1, 2.0, -30000.0],
4983
        [float('inf'), float('inf'), '@class'],
4984
        [[[1], [2], [3]], [1, 2], 3],
4985
    ]
4986

4987
    assert matlabstr2py(
4988
        "SI.hChannels.channelType = {'stripe' 'stripe'}\n"
4989
        "SI.hChannels.channelsActive = 2"
4990
    )['SI.hChannels.channelType'] == ['stripe', 'stripe']
4991

4992
    p = matlabstr2py(
4993
        """
4994
        true = true
4995
        false = false
4996
        True = True
4997
        False = False
4998
        Int = 10
4999
        Float = 3.14
5000
        Float.E = 314.0e-02
5001
        Float.NaN = nan
5002
        Float.Inf = inf
5003
        String = 'string'
5004
        String.Empty = ''
5005
        String.Array = ['ab']
5006
        Array = [1 2]
5007
        Array.2D = [1;2]
5008
        Array.Empty = [[]]
5009
        Transform = [1 0 0;0 1 0;0 0 1]
5010
        Zeros = zeros(1,1)
5011
        Zeros.Empty = zeros(1,0)
5012
        Ones = ones(1,0)
5013
        Filename = C:\\Users\\scanimage.cfg
5014
        Cell = {'' ''}
5015
        Class = @class
5016
        StructObject = <nonscalar struct/object>
5017
        Unknown = unknown
5018

5019
        % Comment
5020
        """
5021
    )
5022
    assert p['Array'] == [1, 2]
5023
    assert p['Array.2D'] == [[1], [2]]
5024
    assert p['Array.Empty'] == []
5025
    assert p['Cell'] == ['', '']
5026
    assert p['Class'] == '@class'
5027
    assert p['False'] is False
5028
    assert p['Filename'] == 'C:\\Users\\scanimage.cfg'
5029
    assert p['Float'] == 3.14
5030
    assert p['Float.E'] == 3.14
5031
    assert p['Float.Inf'] == float('inf')
5032
    # self.assertEqual(p['Float.NaN'], float('nan'))  # can't compare NaN
5033
    assert p['Int'] == 10
5034
    assert p['StructObject'] == '<nonscalar struct/object>'
5035
    assert p['Ones'] == [[]]
5036
    assert p['String'] == 'string'
5037
    assert p['String.Array'] == 'ab'
5038
    assert p['String.Empty'] == ''
5039
    assert p['Transform'] == [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
5040
    assert p['True'] is True
5041
    assert p['Unknown'] == 'unknown'
5042
    assert p['Zeros'] == [[0.0]]
5043
    assert p['Zeros.Empty'] == [[]]
5044
    assert p['false'] is False
5045
    assert p['true'] is True
5046

5047

5048
def test_func_strptime():
5049
    """Test strptime function."""
5050
    now = datetime.datetime.now().replace(microsecond=0)
5051
    assert strptime(now.isoformat()) == now
5052
    assert strptime(now.strftime('%Y:%m:%d %H:%M:%S')) == now
5053
    assert strptime(now.strftime('%Y%m%d %H:%M:%S.%f')) == now
5054

5055

5056
def test_func_hexdump():
5057
    """Test hexdump function."""
5058
    # test hexdump function
5059
    data = binascii.unhexlify(
5060
        '49492a00080000000e00fe0004000100'
5061
        '00000000000000010400010000000001'
5062
        '00000101040001000000000100000201'
5063
        '030001000000200000000301030001'
5064
    )
5065
    # one line
5066
    assert hexdump(data[:16]) == (
5067
        '49 49 2a 00 08 00 00 00 0e 00 fe 00 04 00 01 00 II*.............'
5068
    )
5069
    # height=1
5070
    assert hexdump(data, width=64, height=1) == (
5071
        '49 49 2a 00 08 00 00 00 0e 00 fe 00 04 00 01 00 II*.............'
5072
    )
5073
    # all lines
5074
    assert hexdump(data) == (
5075
        '00: 49 49 2a 00 08 00 00 00 0e 00 fe 00 04 00 01 00 '
5076
        'II*.............\n'
5077
        '10: 00 00 00 00 00 00 00 01 04 00 01 00 00 00 00 01 '
5078
        '................\n'
5079
        '20: 00 00 01 01 04 00 01 00 00 00 00 01 00 00 02 01 '
5080
        '................\n'
5081
        '30: 03 00 01 00 00 00 20 00 00 00 03 01 03 00 01    '
5082
        '...... ........'
5083
    )
5084
    # skip center
5085
    assert hexdump(data, height=3, snipat=0.5) == (
5086
        '00: 49 49 2a 00 08 00 00 00 0e 00 fe 00 04 00 01 00 '
5087
        'II*.............\n'
5088
        '                          ...\n'
5089
        '30: 03 00 01 00 00 00 20 00 00 00 03 01 03 00 01    '
5090
        '...... ........'
5091
    )
5092
    # skip start
5093
    assert hexdump(data, height=3, snipat=0) == (
5094
        '10: 00 00 00 00 00 00 00 01 04 00 01 00 00 00 00 01 '
5095
        '................\n'
5096
        '20: 00 00 01 01 04 00 01 00 00 00 00 01 00 00 02 01 '
5097
        '................\n'
5098
        '30: 03 00 01 00 00 00 20 00 00 00 03 01 03 00 01    '
5099
        '...... ........'
5100
    )
5101
    # skip end
5102
    assert hexdump(data, height=3, snipat=1) == (
5103
        '00: 49 49 2a 00 08 00 00 00 0e 00 fe 00 04 00 01 00 '
5104
        'II*.............\n'
5105
        '10: 00 00 00 00 00 00 00 01 04 00 01 00 00 00 00 01 '
5106
        '................\n'
5107
        '20: 00 00 01 01 04 00 01 00 00 00 00 01 00 00 02 01 '
5108
        '................'
5109
    )
5110

5111

5112
def test_func_asbool():
5113
    """Test asbool function."""
5114
    for true in ('TRUE', ' True ', 'true '):
5115
        assert asbool(true)
5116
        assert asbool(true.encode())
5117
    for false in ('FALSE', ' False ', 'false '):
5118
        assert not asbool(false)
5119
        assert not asbool(false.encode())
5120
    assert asbool('ON', ['on'], ['off'])
5121
    assert asbool('ON', 'on', 'off')
5122
    with pytest.raises(TypeError):
5123
        assert asbool('Yes')
5124
    with pytest.raises(TypeError):
5125
        assert asbool('True', ['on'], ['off'])
5126

5127

5128
def test_func_snipstr():
5129
    """Test snipstr function."""
5130
    # cut middle
5131
    assert snipstr('abc', 3, ellipsis='...') == 'abc'
5132
    assert snipstr('abc', 3, ellipsis='....') == 'abc'
5133
    assert snipstr('abcdefg', 4, ellipsis='') == 'abcd'
5134
    assert snipstr('abcdefg', 4, ellipsis=None) == 'abc…'
5135
    assert snipstr(b'abcdefg', 4, ellipsis=None) == b'a...'
5136
    assert snipstr('abcdefghijklmnop', 8, ellipsis=None) == 'abcd…nop'
5137
    assert snipstr(b'abcdefghijklmnop', 8, ellipsis=None) == b'abc...op'
5138
    assert snipstr('abcdefghijklmnop', 9, ellipsis=None) == 'abcd…mnop'
5139
    assert snipstr(b'abcdefghijklmnop', 9, ellipsis=None) == b'abc...nop'
5140
    assert snipstr('abcdefghijklmnop', 8, ellipsis='..') == 'abc..nop'
5141
    assert snipstr('abcdefghijklmnop', 8, ellipsis='....') == 'ab....op'
5142
    assert snipstr('abcdefghijklmnop', 8, ellipsis='......') == 'ab......'
5143
    # cut right
5144
    assert snipstr('abc', 3, snipat=1, ellipsis='...') == 'abc'
5145
    assert snipstr('abc', 3, snipat=1, ellipsis='....') == 'abc'
5146
    assert snipstr('abcdefg', 4, snipat=1, ellipsis='') == 'abcd'
5147
    assert snipstr('abcdefg', 4, snipat=1, ellipsis=None) == 'abc…'
5148
    assert snipstr(b'abcdefg', 4, snipat=1, ellipsis=None) == b'a...'
5149
    assert (
5150
        snipstr('abcdefghijklmnop', 8, snipat=1, ellipsis=None) == 'abcdefg…'
5151
    )
5152
    assert (
5153
        snipstr(b'abcdefghijklmnop', 8, snipat=1, ellipsis=None) == b'abcde...'
5154
    )
5155
    assert (
5156
        snipstr('abcdefghijklmnop', 9, snipat=1, ellipsis=None) == 'abcdefgh…'
5157
    )
5158
    assert (
5159
        snipstr(b'abcdefghijklmnop', 9, snipat=1, ellipsis=None)
5160
        == b'abcdef...'
5161
    )
5162
    assert (
5163
        snipstr('abcdefghijklmnop', 8, snipat=1, ellipsis='..') == 'abcdef..'
5164
    )
5165
    assert (
5166
        snipstr('abcdefghijklmnop', 8, snipat=1, ellipsis='....') == 'abcd....'
5167
    )
5168
    assert (
5169
        snipstr('abcdefghijklmnop', 8, snipat=1, ellipsis='......')
5170
        == 'ab......'
5171
    )
5172
    # cut left
5173
    assert snipstr('abc', 3, snipat=0, ellipsis='...') == 'abc'
5174
    assert snipstr('abc', 3, snipat=0, ellipsis='....') == 'abc'
5175
    assert snipstr('abcdefg', 4, snipat=0, ellipsis='') == 'defg'
5176
    assert snipstr('abcdefg', 4, snipat=0, ellipsis=None) == '…efg'
5177
    assert snipstr(b'abcdefg', 4, snipat=0, ellipsis=None) == b'...g'
5178
    assert (
5179
        snipstr('abcdefghijklmnop', 8, snipat=0, ellipsis=None) == '…jklmnop'
5180
    )
5181
    assert (
5182
        snipstr(b'abcdefghijklmnop', 8, snipat=0, ellipsis=None) == b'...lmnop'
5183
    )
5184
    assert (
5185
        snipstr('abcdefghijklmnop', 9, snipat=0, ellipsis=None) == '…ijklmnop'
5186
    )
5187
    assert (
5188
        snipstr(b'abcdefghijklmnop', 9, snipat=0, ellipsis=None)
5189
        == b'...klmnop'
5190
    )
5191
    assert (
5192
        snipstr('abcdefghijklmnop', 8, snipat=0, ellipsis='..') == '..klmnop'
5193
    )
5194
    assert (
5195
        snipstr('abcdefghijklmnop', 8, snipat=0, ellipsis='....') == '....mnop'
5196
    )
5197
    assert (
5198
        snipstr('abcdefghijklmnop', 8, snipat=0, ellipsis='......')
5199
        == '......op'
5200
    )
5201

5202

5203
def test_func_pformat_printable_bytes():
5204
    """Test pformat function with printable bytes."""
5205
    value = (
5206
        b'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRST'
5207
        b'UVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'
5208
    )
5209

5210
    assert pformat(value, height=1, width=60, linewidth=None) == (
5211
        '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWX'
5212
    )
5213

5214
    assert (
5215
        pformat(value, height=8, width=60, linewidth=None)
5216
        == r"""
5217
0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWX
5218
""".strip()
5219
    )
5220
    # YZ!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
5221

5222

5223
def test_func_pformat_printable_unicode():
5224
    """Test pformat function with printable unicode."""
5225
    value = (
5226
        '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRST'
5227
        'UVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'
5228
    )
5229

5230
    assert pformat(value, height=1, width=60, linewidth=None) == (
5231
        '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWX'
5232
    )
5233

5234
    assert (
5235
        pformat(value, height=8, width=60, linewidth=None)
5236
        == r"""
5237
0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWX
5238
""".strip()
5239
    )
5240
    # YZ!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
5241

5242

5243
def test_func_pformat_hexdump():
5244
    """Test pformat function with unprintable bytes."""
5245
    value = binascii.unhexlify(
5246
        '49492a00080000000e00fe0004000100'
5247
        '00000000000000010400010000000001'
5248
        '00000101040001000000000100000201'
5249
        '03000100000020000000030103000100'
5250
    )
5251

5252
    assert pformat(value, height=1, width=60, linewidth=None) == (
5253
        '49 49 2a 00 08 00 00 00 0e 00 fe 00 04 00 01 II*............'
5254
    )
5255

5256
    assert (
5257
        pformat(value, height=8, width=70, linewidth=None)
5258
        == """
5259
00: 49 49 2a 00 08 00 00 00 0e 00 fe 00 04 00 01 00 II*.............
5260
10: 00 00 00 00 00 00 00 01 04 00 01 00 00 00 00 01 ................
5261
20: 00 00 01 01 04 00 01 00 00 00 00 01 00 00 02 01 ................
5262
30: 03 00 01 00 00 00 20 00 00 00 03 01 03 00 01 00 ...... .........
5263
""".strip()
5264
    )
5265

5266

5267
def test_func_pformat_dict():
5268
    """Test pformat function with dict."""
5269
    value = {
5270
        'GTCitationGeoKey': 'WGS 84 / UTM zone 29N',
5271
        'GTModelTypeGeoKey': 1,
5272
        'GTRasterTypeGeoKey': 1,
5273
        'KeyDirectoryVersion': 1,
5274
        'KeyRevision': 1,
5275
        'KeyRevisionMinor': 2,
5276
        'ModelTransformation': numpy.array(
5277
            [
5278
                [6.00000e01, 0.00000e00, 0.00000e00, 6.00000e05],
5279
                [0.00000e00, -6.00000e01, 0.00000e00, 5.90004e06],
5280
                [0.00000e00, 0.00000e00, 0.00000e00, 0.00000e00],
5281
                [0.00000e00, 0.00000e00, 0.00000e00, 1.00000e00],
5282
            ]
5283
        ),
5284
        'PCSCitationGeoKey': 'WGS 84 / UTM zone 29N',
5285
        'ProjectedCSTypeGeoKey': 32629,
5286
    }
5287

5288
    assert pformat(value, height=1, width=60, linewidth=None) == (
5289
        "{'GTCitationGeoKey': 'WGS 84 / UTM zone 29N', 'GTModelTypeGe"
5290
    )
5291

5292
    assert pformat(value, height=8, width=60, linewidth=None) == (
5293
        """{'GTCitationGeoKey': 'WGS 84 / UTM zone 29N',
5294
 'GTModelTypeGeoKey': 1,
5295
 'GTRasterTypeGeoKey': 1,
5296
 'KeyDirectoryVersion': 1,
5297
...
5298
       [      0.,       0.,       0.,       0.],
5299
       [      0.,       0.,       0.,       1.]]),
5300
 'PCSCitationGeoKey': 'WGS 84 / UTM zone 29N',
5301
 'ProjectedCSTypeGeoKey': 32629}"""
5302
    )
5303

5304

5305
def test_func_pformat_list():
5306
    """Test pformat function with list."""
5307
    value = (
5308
        60.0,
5309
        0.0,
5310
        0.0,
5311
        600000.0,
5312
        0.0,
5313
        -60.0,
5314
        0.0,
5315
        5900040.0,
5316
        60.0,
5317
        0.0,
5318
        0.0,
5319
        600000.0,
5320
        0.0,
5321
        -60.0,
5322
        0.0,
5323
        5900040.0,
5324
    )
5325

5326
    assert pformat(value, height=1, width=60, linewidth=None) == (
5327
        '(60.0, 0.0, 0.0, 600000.0, 0.0, -60.0, 0.0, 5900040.0, 60.0,'
5328
    )
5329

5330
    assert pformat(value, height=8, width=60, linewidth=None) == (
5331
        '(60.0, 0.0, 0.0, 600000.0, 0.0, -60.0, 0.0, 5900040.0, 60.0,\n'
5332
        ' 0.0, 0.0, 600000.0, 0.0, -60.0, 0.0, 5900040.0)'
5333
    )
5334

5335

5336
def test_func_pformat_numpy():
5337
    """Test pformat function with numpy array."""
5338
    value = numpy.array(
5339
        (
5340
            60.0,
5341
            0.0,
5342
            0.0,
5343
            600000.0,
5344
            0.0,
5345
            -60.0,
5346
            0.0,
5347
            5900040.0,
5348
            60.0,
5349
            0.0,
5350
            0.0,
5351
            600000.0,
5352
            0.0,
5353
            -60.0,
5354
            0.0,
5355
            5900040.0,
5356
        )
5357
    )
5358

5359
    assert pformat(value, height=1, width=60, linewidth=None) == (
5360
        'array([ 60., 0., 0., 600000., 0., -60., 0., 5900040., 60., 0'
5361
    )
5362

5363
    assert pformat(value, height=8, width=60, linewidth=None) == (
5364
        """array([     60.,       0.,       0.,  600000.,       0.,
5365
           -60.,       0., 5900040.,      60.,       0.,
5366
             0.,  600000.,       0.,     -60.,       0.,
5367
       5900040.])"""
5368
    )
5369

5370

5371
@pytest.mark.skipif(not IS_WIN, reason='not reliable on Linux')
5372
def test_func_pformat_xml():
5373
    """Test pformat function with XML."""
5374
    value = """<?xml version="1.0" encoding="ISO-8859-1" ?>
5375
<Dimap_Document name="band2.dim">
5376
  <Metadata_Id>
5377
    <METADATA_FORMAT version="2.12.1">DIMAP</METADATA_FORMAT>
5378
    <METADATA_PROFILE>BEAM-DATAMODEL-V1</METADATA_PROFILE>
5379
  </Metadata_Id>
5380
  <Image_Interpretation>
5381
    <Spectral_Band_Info>
5382
      <BAND_INDEX>0</BAND_INDEX>
5383
    </Spectral_Band_Info>
5384
  </Image_Interpretation>
5385
</Dimap_Document>"""
5386

5387
    assert pformat(value, height=1, width=60, linewidth=None) == (
5388
        '<?xml version="1.0" encoding="ISO-8859-1" ?> <Dimap_Document'
5389
    )
5390

5391
    assert pformat(value, height=8, width=60, linewidth=None) == (
5392
        """<?xml version='1.0' encoding='ISO-8859-1'?>
5393
<Dimap_Document name="band2.dim">
5394
 <Metadata_Id>
5395
  <METADATA_FORMAT version="2.12.1">DIMAP</METADATA_FORMAT>
5396
...
5397
   <BAND_INDEX>0</BAND_INDEX>
5398
  </Spectral_Band_Info>
5399
 </Image_Interpretation>
5400
</Dimap_Document>"""
5401
    )
5402

5403

5404
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_LARGE, reason=REASON)
5405
def test_func_lsm2bin():
5406
    """Test lsm2bin function."""
5407
    # Convert LSM to BIN
5408
    fname = private_file(
5409
        'lsm/Twoareas_Zstacks54slices_3umintervals_5cycles.lsm'
5410
    )
5411
    # fname = private_file(
5412
    #     'LSM/fish01-wt-t01-10_ForTest-20zplanes10timepoints.lsm')
5413
    lsm2bin(fname, '', verbose=True)
5414

5415

5416
def test_func_tiffcomment():
5417
    """Test tiffcomment function."""
5418
    data = random_data(numpy.uint8, (33, 31, 3))
5419
    with TempFileName('func_tiffcomment') as fname:
5420
        comment = 'A comment'
5421
        imwrite(
5422
            fname,
5423
            data,
5424
            photometric=PHOTOMETRIC.RGB,
5425
            description=comment,
5426
            metadata=None,
5427
        )
5428
        assert comment == tiffcomment(fname)
5429
        comment = 'changed comment'
5430
        tiffcomment(fname, comment)
5431
        assert comment == tiffcomment(fname)
5432
        assert_valid_tiff(fname)
5433

5434

5435
def test_func_create_output():
5436
    """Test create_output function."""
5437
    shape = (16, 17)
5438
    dtype = numpy.uint16
5439
    # None
5440
    a = create_output(None, shape, dtype)
5441
    assert_array_equal(a, numpy.zeros(shape, dtype))
5442
    # existing array
5443
    b = create_output(a, a.shape, a.dtype)
5444
    assert a is b.base
5445
    # 'memmap'
5446
    a = create_output('memmap', shape, dtype)
5447
    assert isinstance(a, numpy.memmap)
5448
    del a
5449
    # 'memmap:tempdir'
5450
    a = create_output(f'memmap:{os.path.abspath(TEMP_DIR)}', shape, dtype)
5451
    assert isinstance(a, numpy.memmap)
5452
    del a
5453
    # filename
5454
    with TempFileName('nopages') as fname:
5455
        a = create_output(fname, shape, dtype)
5456
        del a
5457

5458

5459
def test_func_reorient():
5460
    """Test reoirient func."""
5461
    data = numpy.zeros((2, 3, 31, 33, 3), numpy.uint8)
5462
    for orientation in range(1, 9):
5463
        reorient(data, orientation)  # TODO: assert result
5464

5465

5466
@pytest.mark.parametrize('key', [None, 0, 3, 'series'])
5467
@pytest.mark.parametrize('out', [None, 'empty', 'memmap', 'dir', 'name'])
5468
def test_func_create_output_asarray(out, key):
5469
    """Test create_output function in context of asarray."""
5470
    data = random_data(numpy.uint16, (5, 219, 301))
5471

5472
    with TempFileName(f'func_out_{key}_{out}') as fname:
5473
        imwrite(fname, data)
5474
        # assert file
5475
        with TiffFile(fname) as tif:
5476
            tif.pages.useframes = True
5477
            tif.pages._load()
5478

5479
            if key is None:
5480
                # default
5481
                obj = tif
5482
                dat = data
5483
            elif key == 'series':
5484
                # series
5485
                obj = tif.series[0]
5486
                dat = data
5487
            else:
5488
                # single page/frame
5489
                obj = tif.pages[key]
5490
                dat = data[key]
5491
                if key == 0:
5492
                    assert isinstance(obj, TiffPage)
5493
                else:
5494
                    assert isinstance(obj, TiffFrame)
5495

5496
            if out is None:
5497
                # new array
5498
                image = obj.asarray(out=None)
5499
                assert_array_equal(dat, image)
5500
                del image
5501
            elif out == 'empty':
5502
                # existing array
5503
                image = numpy.empty_like(dat)
5504
                obj.asarray(out=image)
5505
                assert_array_equal(dat, image)
5506
                del image
5507
            elif out == 'memmap':
5508
                # memmap in temp dir
5509
                image = obj.asarray(out='memmap')
5510
                assert isinstance(image, numpy.memmap)
5511
                assert_array_equal(dat, image)
5512
                del image
5513
            elif out == 'dir':
5514
                # memmap in specified dir
5515
                tempdir = os.path.dirname(fname)
5516
                image = obj.asarray(out=f'memmap:{tempdir}')
5517
                assert isinstance(image, numpy.memmap)
5518
                assert_array_equal(dat, image)
5519
                del image
5520
            elif out == 'name':
5521
                # memmap in specified file
5522
                with TempFileName(
5523
                    f'out_{key}_{out}', ext='.memmap'
5524
                ) as fileout:
5525
                    image = obj.asarray(out=fileout)
5526
                    assert isinstance(image, numpy.memmap)
5527
                    assert_array_equal(dat, image)
5528
                    del image
5529

5530

5531
def test_func_bitorder_decode():
5532
    """Test bitorder_decode function."""
5533
    from tifffile._imagecodecs import bitorder_decode
5534

5535
    # bytes
5536
    assert bitorder_decode(b'\x01\x64') == b'\x80&'
5537
    assert bitorder_decode(b'\x01\x00\x9a\x02') == b'\x80\x00Y@'
5538

5539
    # numpy array
5540
    data = numpy.array([1, 666], dtype=numpy.uint16)
5541
    reverse = numpy.array([128, 16473], dtype=numpy.uint16)
5542
    # return new array
5543
    assert_array_equal(bitorder_decode(data), reverse)
5544
    # array view not supported
5545
    data = numpy.array(
5546
        [
5547
            [1, 666, 1431655765, 62],
5548
            [2, 667, 2863311530, 32],
5549
            [3, 668, 1431655765, 30],
5550
        ],
5551
        dtype=numpy.uint32,
5552
    )
5553
    reverse = numpy.array(
5554
        [
5555
            [1, 666, 1431655765, 62],
5556
            [2, 16601, 1431655765, 32],
5557
            [3, 16441, 2863311530, 30],
5558
        ],
5559
        dtype=numpy.uint32,
5560
    )
5561
    # if int(numpy.__version__.split('.')[1]) < 23:
5562
    #     with pytest.raises(NotImplementedError):
5563
    #         bitorder_decode(data[1:, 1:3])
5564
    # else:
5565
    assert_array_equal(bitorder_decode(data[1:, 1:3]), reverse[1:, 1:3])
5566

5567

5568
@pytest.mark.parametrize(
5569
    'kind',
5570
    ['u1', 'u2', 'u4', 'u8', 'i1', 'i2', 'i4', 'i8', 'f4', 'f8', 'B'],
5571
)
5572
@pytest.mark.parametrize('byteorder', ['>', '<'])
5573
def test_func_delta_codec(byteorder, kind):
5574
    """Test delta codec functions."""
5575
    from tifffile._imagecodecs import delta_decode, delta_encode
5576

5577
    # if byteorder == '>' and numpy.dtype(kind).itemsize == 1:
5578
    #     pytest.skip('duplicate test')
5579

5580
    if kind[0] in 'iuB':
5581
        low = numpy.iinfo(kind).min
5582
        high = numpy.iinfo(kind).max
5583
        data = numpy.random.randint(
5584
            low, high, size=33 * 31 * 3, dtype=kind
5585
        ).reshape(33, 31, 3)
5586
    else:
5587
        # floating point
5588
        if byteorder == '>':
5589
            pytest.xfail('requires imagecodecs')
5590
        low, high = -1e5, 1e5
5591
        data = numpy.random.randint(
5592
            low, high, size=33 * 31 * 3, dtype='i4'
5593
        ).reshape(33, 31, 3)
5594
    data = data.astype(byteorder + kind)
5595

5596
    data[16, 14] = [0, 0, 0]
5597
    data[16, 15] = [low, high, low]
5598
    data[16, 16] = [high, low, high]
5599
    data[16, 17] = [low, high, low]
5600
    data[16, 18] = [high, low, high]
5601
    data[16, 19] = [0, 0, 0]
5602

5603
    if kind == 'B':
5604
        # data = data.reshape(-1)
5605
        data = data.tobytes()
5606
        assert delta_decode(delta_encode(data)) == data
5607
    else:
5608
        encoded = delta_encode(data, axis=-2)
5609
        assert encoded.dtype.byteorder == data.dtype.byteorder
5610
        assert_array_equal(data, delta_decode(encoded, axis=-2))
5611
        if not SKIP_CODECS:
5612
            assert_array_equal(
5613
                encoded, imagecodecs.delta_encode(data, axis=-2)
5614
            )
5615

5616

5617
@pytest.mark.parametrize('length', [0, 2, 31 * 33 * 3])
5618
@pytest.mark.parametrize('codec', ['lzma', 'zlib'])
5619
def test_func_zlib_lzma_codecs(codec, length):
5620
    """Test zlib and lzma codec functions."""
5621
    if codec == 'zlib':
5622
        from tifffile._imagecodecs import zlib_decode, zlib_encode
5623

5624
        encode = zlib_encode
5625
        decode = zlib_decode
5626
    elif codec == 'lzma':
5627
        from tifffile._imagecodecs import lzma_decode, lzma_encode
5628

5629
        encode = lzma_encode
5630
        decode = lzma_decode
5631

5632
    if length:
5633
        data = numpy.random.randint(255, size=length, dtype=numpy.uint8)
5634
        assert decode(encode(data)) == data.tobytes()
5635
    else:
5636
        data = b''
5637
        assert decode(encode(data)) == data
5638

5639

5640
PACKBITS_DATA = [
5641
    ([], b''),
5642
    ([0] * 1, b'\x00\x00'),  # literal
5643
    ([0] * 2, b'\xff\x00'),  # replicate
5644
    ([0] * 3, b'\xfe\x00'),
5645
    ([0] * 64, b'\xc1\x00'),
5646
    ([0] * 127, b'\x82\x00'),
5647
    ([0] * 128, b'\x81\x00'),  # max replicate
5648
    ([0] * 129, b'\x81\x00\x00\x00'),
5649
    ([0] * 130, b'\x81\x00\xff\x00'),
5650
    ([0] * 128 * 3, b'\x81\x00' * 3),
5651
    ([255] * 1, b'\x00\xff'),  # literal
5652
    ([255] * 2, b'\xff\xff'),  # replicate
5653
    ([0, 1], b'\x01\x00\x01'),
5654
    ([0, 1, 2], b'\x02\x00\x01\x02'),
5655
    ([0, 1] * 32, b'\x3f' + b'\x00\x01' * 32),
5656
    ([0, 1] * 63 + [2], b'\x7e' + b'\x00\x01' * 63 + b'\x02'),
5657
    ([0, 1] * 64, b'\x7f' + b'\x00\x01' * 64),  # max literal
5658
    ([0, 1] * 64 + [2], b'\x7f' + b'\x00\x01' * 64 + b'\x00\x02'),
5659
    ([0, 1] * 64 * 5, (b'\x7f' + b'\x00\x01' * 64) * 5),
5660
    ([0, 1, 1], b'\x00\x00\xff\x01'),  # or b'\x02\x00\x01\x01'
5661
    ([0] + [1] * 128, b'\x00\x00\x81\x01'),  # or b'\x01\x00\x01\x82\x01'
5662
    ([0] + [1] * 129, b'\x00\x00\x81\x01\x00\x01'),  # b'\x01\x00\x01\x81\x01'
5663
    ([0, 1] * 64 + [2] * 2, b'\x7f' + b'\x00\x01' * 64 + b'\xff\x02'),
5664
    ([0, 1] * 64 + [2] * 128, b'\x7f' + b'\x00\x01' * 64 + b'\x81\x02'),
5665
    ([0, 0, 1], b'\x02\x00\x00\x01'),  # or b'\xff\x00\x00\x01'
5666
    ([0, 0] + [1, 2] * 64, b'\xff\x00\x7f' + b'\x01\x02' * 64),
5667
    ([0] * 128 + [1], b'\x81\x00\x00\x01'),
5668
    ([0] * 128 + [1, 2] * 64, b'\x81\x00\x7f' + b'\x01\x02' * 64),
5669
    (
5670
        b'\xaa\xaa\xaa\x80\x00\x2a\xaa\xaa\xaa\xaa\x80\x00'
5671
        b'\x2a\x22\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa',
5672
        b'\xfe\xaa\x02\x80\x00\x2a\xfd\xaa\x03\x80\x00\x2a\x22\xf7\xaa',
5673
    ),
5674
]
5675

5676

5677
@pytest.mark.parametrize('data', range(len(PACKBITS_DATA)))
5678
def test_func_packbits_decode(data):
5679
    """Test packbits_decode function."""
5680
    from tifffile._imagecodecs import packbits_decode
5681

5682
    uncompressed, compressed = PACKBITS_DATA[data]
5683
    assert packbits_decode(compressed) == bytes(uncompressed)
5684

5685

5686
def test_func_packints_decode():
5687
    """Test packints_decode function."""
5688
    from tifffile._imagecodecs import packints_decode
5689

5690
    decoded = packints_decode(b'', 'B', 1)
5691
    assert len(decoded) == 0
5692
    decoded = packints_decode(b'a', 'B', 1)
5693
    assert tuple(decoded) == (0, 1, 1, 0, 0, 0, 0, 1)
5694
    with pytest.raises(NotImplementedError):
5695
        decoded = packints_decode(b'ab', 'B', 2)
5696
        assert tuple(decoded) == (1, 2, 0, 1, 1, 2, 0, 2)
5697
    with pytest.raises(NotImplementedError):
5698
        decoded = packints_decode(b'abcd', 'B', 3)
5699
        assert tuple(decoded) == (3, 0, 2, 6, 1, 1, 4, 3, 3, 1)
5700

5701

5702
def test_func_check_shape():
5703
    """Test check_shape function."""
5704
    assert check_shape((10, 10, 4), (10, 10, 4))
5705
    assert check_shape((10, 10, 4), (1, 1, 10, 10, 4))
5706
    assert not check_shape((4, 10, 10), (10, 10, 4))
5707
    assert not check_shape((10, 10, 4), (4, 10, 10))
5708
    assert not check_shape((10, 10, 4), (1, 1, 4, 10, 10))
5709

5710
    assert check_shape((0,), (0, 0))
5711
    assert check_shape((0, 0), (0,))
5712

5713
    assert check_shape((4,), (4,))
5714
    assert check_shape((1, 4), (4,))
5715
    assert check_shape((1, 4), (4, 1))
5716
    assert check_shape((4, 1), (4, 1))
5717
    assert check_shape((4, 1), (1, 4, 1))
5718
    assert check_shape((4, 5), (4, 5, 1))
5719
    assert check_shape((4, 5), (4, 5, 1, 1))
5720
    assert check_shape((4, 5), (1, 4, 5, 1))
5721

5722
    assert not check_shape((1,), (0, 0))
5723
    assert not check_shape((1, 0), (1,))
5724
    assert not check_shape((4, 1), (1,))
5725
    assert not check_shape((4, 1), (2,))
5726
    assert not check_shape((4, 1), (4,))
5727
    assert not check_shape((4, 1), (2, 2))
5728
    assert not check_shape((4, 1), (2, 1))
5729
    assert not check_shape((3, 4, 5), (4, 5, 3))
5730

5731

5732
###############################################################################
5733

5734
# Test FileHandle class
5735

5736
FILEHANDLE_NAME = public_file('tifffile/test_FileHandle.bin')
5737
FILEHANDLE_SIZE = 7937381
5738
FILEHANDLE_OFFSET = 333
5739
FILEHANDLE_LENGTH = 7937381 - 666
5740

5741

5742
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
5743
def create_filehandle_file():
5744
    """Write test_FileHandle.bin file."""
5745
    # array start 999
5746
    # array end 1254
5747
    # recarray start 2253
5748
    # recarray end 6078
5749
    # tiff start 7077
5750
    # tiff end 12821
5751
    # mm offset = 13820
5752
    # mm size = 7936382
5753
    with open(FILEHANDLE_NAME, 'wb') as fh:
5754
        # buffer
5755
        numpy.ones(999, dtype=numpy.uint8).tofile(fh)
5756
        # array
5757
        print('array start', fh.tell())
5758
        numpy.arange(255, dtype=numpy.uint8).tofile(fh)
5759
        print('array end', fh.tell())
5760
        # buffer
5761
        numpy.ones(999, dtype=numpy.uint8).tofile(fh)
5762
        # recarray
5763
        print('recarray start', fh.tell())
5764
        a = numpy.recarray(
5765
            (255, 3), dtype=[('x', numpy.float32), ('y', numpy.uint8)]
5766
        )
5767
        for i in range(3):
5768
            a[:, i].x = numpy.arange(255, dtype=numpy.float32)
5769
            a[:, i].y = numpy.arange(255, dtype=numpy.uint8)
5770
        a.tofile(fh)
5771
        print('recarray end', fh.tell())
5772
        # buffer
5773
        numpy.ones(999, dtype=numpy.uint8).tofile(fh)
5774
        # tiff
5775
        print('tiff start', fh.tell())
5776
        with open('data/public/tifffile/generic_series.tif', 'rb') as tif:
5777
            fh.write(tif.read())
5778
        print('tiff end', fh.tell())
5779
        # buffer
5780
        numpy.ones(999, dtype=numpy.uint8).tofile(fh)
5781
        # micromanager
5782
        print('micromanager start', fh.tell())
5783
        with open('data/public/tifffile/micromanager.tif', 'rb') as tif:
5784
            fh.write(tif.read())
5785
        print('micromanager end', fh.tell())
5786
        # buffer
5787
        numpy.ones(999, dtype=numpy.uint8).tofile(fh)
5788

5789

5790
def assert_filehandle(fh, offset=0):
5791
    """Assert filehandle can read test_FileHandle.bin."""
5792
    assert__repr__(fh)
5793
    assert not fh.closed
5794
    assert fh.open() is None  # open an open file
5795
    fh.close()
5796
    # assert fh.closed
5797
    assert fh.open() is None  # open a closed file
5798
    size = FILEHANDLE_SIZE - 2 * offset
5799
    pad = 999 - offset
5800
    assert fh.size == size
5801
    assert fh.tell() == 0
5802
    assert fh.read(4) == b'\x01\x01\x01\x01'
5803
    fh.seek(pad - 4)
5804
    assert fh.tell() == pad - 4
5805
    assert fh.read(4) == b'\x01\x01\x01\x01'
5806
    fh.seek(-4, whence=1)
5807
    assert fh.tell() == pad - 4
5808
    assert fh.read(4) == b'\x01\x01\x01\x01'
5809
    fh.seek(-pad, whence=2)
5810
    assert fh.tell() == size - pad
5811
    assert fh.read(4) == b'\x01\x01\x01\x01'
5812
    # assert array
5813
    fh.seek(pad, whence=0)
5814
    assert fh.tell() == pad
5815
    assert_array_equal(
5816
        fh.read_array(numpy.uint8, 255), numpy.arange(255, dtype=numpy.uint8)
5817
    )
5818
    # assert records
5819
    fh.seek(999, whence=1)
5820
    assert fh.tell() == 2253 - offset
5821
    records = fh.read_record(
5822
        [('x', numpy.float32), ('y', numpy.uint8)], (255, 3)
5823
    )
5824
    assert_array_equal(records.y[:, 0], range(255))
5825
    assert_array_equal(records.x, records.y)
5826
    # assert memmap
5827
    if fh.is_file:
5828
        assert_array_equal(
5829
            fh.memmap_array(numpy.uint8, 255, pad),
5830
            numpy.arange(255, dtype=numpy.uint8),
5831
        )
5832

5833

5834
@pytest.mark.skipif(SKIP_HTTP, reason=REASON)
5835
def test_filehandle_seekable():
5836
    """Test FileHandle must be seekable."""
5837
    from urllib.request import HTTPHandler, build_opener
5838

5839
    opener = build_opener(HTTPHandler())
5840
    opener.addheaders = [('User-Agent', 'test_tifffile.py')]
5841
    try:
5842
        fh = opener.open(URL + 'test/test_http.tif')
5843
    except OSError:
5844
        pytest.skip(URL + 'test/test_http.tif')
5845

5846
    with pytest.raises(ValueError):
5847
        FileHandle(fh)
5848

5849

5850
def test_filehandle_write_bytesio():
5851
    """Test write to FileHandle from BytesIO."""
5852
    value = b'123456789'
5853
    buf = BytesIO()
5854
    with FileHandle(buf) as fh:
5855
        fh.write(value)
5856
    assert buf.getvalue() == value
5857

5858

5859
def test_filehandle_write_bytesio_offset():
5860
    """Test write to FileHandle from BytesIO with offset."""
5861
    pad = b'abcd'
5862
    value = b'123456789'
5863
    buf = BytesIO()
5864
    buf.write(pad)
5865
    with FileHandle(buf) as fh:
5866
        fh.write(value)
5867
    buf.write(pad)
5868
    # assert buffer
5869
    buf.seek(len(pad))
5870
    assert buf.read(len(value)) == value
5871
    buf.seek(2)
5872
    with FileHandle(buf, offset=len(pad), size=len(value)) as fh:
5873
        assert fh.read(len(value)) == value
5874

5875

5876
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
5877
def test_filehandle_filename():
5878
    """Test FileHandle from filename."""
5879
    with FileHandle(FILEHANDLE_NAME) as fh:
5880
        assert fh.name == 'test_FileHandle.bin'
5881
        assert fh.is_file
5882
        assert_filehandle(fh)
5883

5884

5885
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
5886
def test_filehandle_filename_offset():
5887
    """Test FileHandle from filename with offset."""
5888
    with FileHandle(
5889
        FILEHANDLE_NAME, offset=FILEHANDLE_OFFSET, size=FILEHANDLE_LENGTH
5890
    ) as fh:
5891
        assert fh.name == 'test_FileHandle.bin'
5892
        assert fh.is_file
5893
        assert_filehandle(fh, FILEHANDLE_OFFSET)
5894

5895

5896
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
5897
def test_filehandle_bytesio():
5898
    """Test FileHandle from BytesIO."""
5899
    with open(FILEHANDLE_NAME, 'rb') as fh:
5900
        stream = BytesIO(fh.read())
5901
    with FileHandle(stream) as fh:
5902
        assert fh.name == 'Unnamed binary stream'
5903
        assert not fh.is_file
5904
        assert_filehandle(fh)
5905

5906

5907
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
5908
def test_filehandle_bytesio_offset():
5909
    """Test FileHandle from BytesIO with offset."""
5910
    with open(FILEHANDLE_NAME, 'rb') as fh:
5911
        stream = BytesIO(fh.read())
5912
    with FileHandle(
5913
        stream, offset=FILEHANDLE_OFFSET, size=FILEHANDLE_LENGTH
5914
    ) as fh:
5915
        assert fh.name == 'Unnamed binary stream'
5916
        assert not fh.is_file
5917
        assert_filehandle(fh, offset=FILEHANDLE_OFFSET)
5918

5919

5920
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
5921
def test_filehandle_openfile():
5922
    """Test FileHandle from open file."""
5923
    with open(FILEHANDLE_NAME, 'rb') as fhandle:
5924
        with FileHandle(fhandle) as fh:
5925
            assert fh.name == 'test_FileHandle.bin'
5926
            assert fh.is_file
5927
            assert_filehandle(fh)
5928
        assert not fhandle.closed
5929

5930

5931
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
5932
def test_filehandle_openfile_offset():
5933
    """Test FileHandle from open file with offset."""
5934
    with open(FILEHANDLE_NAME, 'rb') as fhandle:
5935
        with FileHandle(
5936
            fhandle, offset=FILEHANDLE_OFFSET, size=FILEHANDLE_LENGTH
5937
        ) as fh:
5938
            assert fh.name == 'test_FileHandle.bin'
5939
            assert fh.is_file
5940
            assert_filehandle(fh, offset=FILEHANDLE_OFFSET)
5941
        assert not fhandle.closed
5942

5943

5944
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
5945
def test_filehandle_filehandle():
5946
    """Test FileHandle from other FileHandle."""
5947
    with FileHandle(FILEHANDLE_NAME, 'rb') as fhandle:
5948
        with FileHandle(fhandle) as fh:
5949
            assert fh.name == 'test_FileHandle.bin'
5950
            assert fh.is_file
5951
            assert_filehandle(fh)
5952
        assert not fhandle.closed
5953

5954

5955
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
5956
def test_filehandle_offset():
5957
    """Test FileHandle from other FileHandle with offset."""
5958
    with FileHandle(FILEHANDLE_NAME, 'rb') as fhandle:
5959
        with FileHandle(
5960
            fhandle, offset=FILEHANDLE_OFFSET, size=FILEHANDLE_LENGTH
5961
        ) as fh:
5962
            assert fh.name == 'test_FileHandle@333.bin'
5963
            assert fh.is_file
5964
            assert_filehandle(fh, offset=FILEHANDLE_OFFSET)
5965
        assert not fhandle.closed
5966

5967

5968
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
5969
def test_filehandle_reopen():
5970
    """Test FileHandle close and open."""
5971
    try:
5972
        fh = FileHandle(FILEHANDLE_NAME)
5973
        assert not fh.closed
5974
        assert fh.is_file
5975
        fh.close()
5976
        assert fh.closed
5977
        fh.open()
5978
        assert not fh.closed
5979
        assert fh.is_file
5980
        assert fh.name == 'test_FileHandle.bin'
5981
        assert_filehandle(fh)
5982
    finally:
5983
        fh.close()
5984

5985

5986
@pytest.mark.skipif(SKIP_HTTP or not IS_CG, reason=REASON)
5987
def test_filehandle_unc_path():
5988
    """Test FileHandle from UNC path."""
5989
    with FileHandle(r'\\localhost\test$\test_FileHandle.bin') as fh:
5990
        assert fh.name == 'test_FileHandle.bin'
5991
        assert fh.dirname == '\\\\localhost\\test$\\'
5992
        assert_filehandle(fh)
5993

5994

5995
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_ZARR, reason=REASON)
5996
def test_filehandle_fsspec_localfileopener():
5997
    """Test FileHandle from fsspec LocalFileOpener."""
5998
    with fsspec.open(FILEHANDLE_NAME, 'rb') as fhandle:
5999
        with FileHandle(fhandle) as fh:
6000
            assert fh.name == 'test_FileHandle.bin'
6001
            assert fh.is_file  # fails with fsspec 2022.7
6002
            assert_filehandle(fh)
6003
        assert not fhandle.closed
6004

6005

6006
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_ZARR, reason=REASON)
6007
def test_filehandle_fsspec_openfile():
6008
    """Test FileHandle from fsspec OpenFile."""
6009
    fhandle = fsspec.open(FILEHANDLE_NAME, 'rb')
6010
    with FileHandle(fhandle) as fh:
6011
        assert fh.name == 'test_FileHandle.bin'
6012
        assert fh.is_file
6013
        assert_filehandle(fh)
6014
    fhandle.close()
6015

6016

6017
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_HTTP or SKIP_ZARR, reason=REASON)
6018
def test_filehandle_fsspec_http():
6019
    """Test FileHandle from HTTP via fsspec."""
6020
    with fsspec.open(URL + 'test/test_FileHandle.bin', 'rb') as fhandle:
6021
        with FileHandle(fhandle) as fh:
6022
            assert fh.name == 'test_FileHandle.bin'
6023
            assert not fh.is_file
6024
            assert_filehandle(fh)
6025
        assert not fhandle.closed
6026

6027

6028
def test_filehandle_exclusive_creation():
6029
    """Test FileHandle with exclusive creation mode 'x'."""
6030
    # https://github.com/cgohlke/tifffile/issues/221
6031
    with TempFileName('read_filehandle_exclusive', ext='.bin') as fname:
6032
        if os.path.exists(fname):
6033
            os.remove(fname)
6034
        with FileHandle(fname, mode='x'):
6035
            pass
6036
        with pytest.raises(FileExistsError):
6037
            with FileHandle(fname, mode='x'):
6038
                pass
6039

6040

6041
###############################################################################
6042

6043
# Test read specific files
6044

6045
if SKIP_EXTENDED or SKIP_PRIVATE:
6046
    TIGER_FILES = []
6047
    TIGER_IDS = []
6048
else:
6049
    TIGER_FILES = (
6050
        public_file('graphicsmagick.org/be/*.tif')
6051
        + public_file('graphicsmagick.org/le/*.tif')
6052
        + public_file('graphicsmagick.org/bigtiff-be/*.tif')
6053
        + public_file('graphicsmagick.org/bigtiff-le/*.tif')
6054
    )
6055
    TIGER_IDS = [
6056
        '-'.join(f.split(os.path.sep)[-2:])
6057
        .replace('-tiger', '')
6058
        .replace('.tif', '')
6059
        for f in TIGER_FILES
6060
    ]
6061

6062

6063
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_CODECS or SKIP_EXTENDED, reason=REASON)
6064
@pytest.mark.parametrize('fname', TIGER_FILES, ids=TIGER_IDS)
6065
def test_read_tigers(fname):
6066
    """Test tiger images from GraphicsMagick."""
6067
    # ftp://ftp.graphicsmagick.org/pub/tiff-samples
6068
    with TiffFile(fname) as tif:
6069
        byteorder = {'le': '<', 'be': '>'}[os.path.split(fname)[0][-2:]]
6070
        databits = int(fname.rsplit('.tif')[0][-2:])
6071

6072
        # assert file properties
6073
        assert_file_flags(tif)
6074
        assert tif.byteorder == byteorder
6075
        assert tif.is_bigtiff == ('bigtiff' in fname)
6076
        assert len(tif.pages) == 1
6077

6078
        # assert page properties
6079
        page = tif.pages.first
6080
        assert_page_flags(page)
6081
        assert page.tags['DocumentName'].value == os.path.basename(fname)
6082
        assert page.imagewidth == 73
6083
        assert page.imagelength == 76
6084
        assert page.bitspersample == databits
6085
        assert (page.photometric == PHOTOMETRIC.RGB) == ('rgb' in fname)
6086
        assert (page.photometric == PHOTOMETRIC.PALETTE) == (
6087
            'palette' in fname
6088
        )
6089
        assert page.is_tiled == ('tile' in fname)
6090
        assert (page.planarconfig == PLANARCONFIG.CONTIG) == (
6091
            'planar' not in fname
6092
        )
6093
        if 'minisblack' in fname:
6094
            assert page.photometric == PHOTOMETRIC.MINISBLACK
6095

6096
        # float24 not supported
6097
        # if 'float' in fname and databits == 24:
6098
        #     with pytest.raises(ValueError):
6099
        #         data = tif.asarray()
6100
        #     return
6101

6102
        # assert data shapes
6103
        data = tif.asarray()
6104
        assert isinstance(data, numpy.ndarray)
6105
        assert data.flags['C_CONTIGUOUS']
6106
        # if 'palette' in fname:
6107
        #     shape = (76, 73, 3)
6108
        if 'rgb' in fname:
6109
            if 'planar' in fname:
6110
                shape = (3, 76, 73)
6111
            else:
6112
                shape = (76, 73, 3)
6113
        elif 'separated' in fname:
6114
            if 'planar' in fname:
6115
                shape = (4, 76, 73)
6116
            else:
6117
                shape = (76, 73, 4)
6118
        else:
6119
            shape = (76, 73)
6120
        assert data.shape == shape
6121

6122
        # assert data types
6123
        if 'float' in fname:
6124
            if databits == 24:
6125
                dtype = numpy.float32
6126
            else:
6127
                dtype = f'float{databits}'
6128
        # elif 'palette' in fname:
6129
        #     dtype = numpy.uint16
6130
        elif databits == 1:
6131
            dtype = numpy.bool_
6132
        elif databits <= 8:
6133
            dtype = numpy.uint8
6134
        elif databits <= 16:
6135
            dtype = numpy.uint16
6136
        elif databits <= 32:
6137
            dtype = numpy.uint32
6138
        elif databits <= 64:
6139
            dtype = numpy.uint64
6140
        assert data.dtype == dtype
6141

6142
        assert_decode_method(page, data)
6143
        assert_aszarr_method(page, data)
6144
        assert__str__(tif)
6145

6146

6147
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
6148
def test_read_exif_paint():
6149
    """Test read EXIF tags."""
6150
    fname = private_file('exif/paint.tif')
6151
    with TiffFile(fname) as tif:
6152
        exif = tif.pages.first.tags['ExifTag'].value
6153
        assert exif['ColorSpace'] == 65535
6154
        assert exif['ExifVersion'] == '0230'
6155
        assert exif['UserComment'] == 'paint'
6156
        assert tif.fstat.st_size == 4234366
6157
        assert_aszarr_method(tif)
6158
        assert__str__(tif)
6159

6160

6161
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_CODECS, reason=REASON)
6162
def test_read_hopper_2bit():
6163
    """Test read 2-bit, fillorder=lsb2msb."""
6164
    # https://github.com/python-pillow/Pillow/pull/1789
6165
    fname = public_file('pillow/tiff_gray_2_4_bpp/hopper2.tif')
6166
    with TiffFile(fname) as tif:
6167
        assert tif.byteorder == '<'
6168
        assert len(tif.pages) == 1
6169
        assert len(tif.series) == 1
6170
        # assert page properties
6171
        page = tif.pages.first
6172
        assert page.photometric == PHOTOMETRIC.MINISBLACK
6173
        assert not page.is_contiguous
6174
        assert page.compression == COMPRESSION.NONE
6175
        assert page.imagewidth == 128
6176
        assert page.imagelength == 128
6177
        assert page.bitspersample == 2
6178
        assert page.samplesperpixel == 1
6179
        # assert series properties
6180
        series = tif.series[0]
6181
        assert series.shape == (128, 128)
6182
        assert series.dtype == numpy.uint8
6183
        assert series.axes == 'YX'
6184
        assert series.kind == 'uniform'
6185
        assert series.dataoffset is None
6186
        # assert data
6187
        data = tif.asarray()
6188
        assert isinstance(data, numpy.ndarray)
6189
        assert data.shape == (128, 128)
6190
        assert data[50, 63] == 3
6191
        assert_aszarr_method(tif, data)
6192
        assert__str__(tif)
6193
    # reversed
6194
    fname = public_file('pillow/tiff_gray_2_4_bpp/hopper2R.tif')
6195
    with TiffFile(fname) as tif:
6196
        page = tif.pages.first
6197
        assert page.photometric == PHOTOMETRIC.MINISBLACK
6198
        assert page.fillorder == FILLORDER.LSB2MSB
6199
        assert_array_equal(tif.asarray(), data)
6200
        assert_aszarr_method(tif)
6201
        assert__str__(tif)
6202
    # inverted
6203
    fname = public_file('pillow/tiff_gray_2_4_bpp/hopper2I.tif')
6204
    with TiffFile(fname) as tif:
6205
        page = tif.pages.first
6206
        assert page.photometric == PHOTOMETRIC.MINISWHITE
6207
        assert_array_equal(tif.asarray(), 3 - data)
6208
        assert_aszarr_method(tif)
6209
        assert__str__(tif)
6210
    # inverted and reversed
6211
    fname = public_file('pillow/tiff_gray_2_4_bpp/hopper2IR.tif')
6212
    with TiffFile(fname) as tif:
6213
        page = tif.pages.first
6214
        assert page.photometric == PHOTOMETRIC.MINISWHITE
6215
        assert_array_equal(tif.asarray(), 3 - data)
6216
        assert_aszarr_method(tif)
6217
        assert__str__(tif)
6218

6219

6220
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_CODECS, reason=REASON)
6221
def test_read_hopper_4bit():
6222
    """Test read 4-bit, fillorder=lsb2msb."""
6223
    # https://github.com/python-pillow/Pillow/pull/1789
6224
    fname = public_file('pillow/tiff_gray_2_4_bpp/hopper4.tif')
6225
    with TiffFile(fname) as tif:
6226
        assert tif.byteorder == '<'
6227
        assert len(tif.pages) == 1
6228
        assert len(tif.series) == 1
6229
        # assert page properties
6230
        page = tif.pages.first
6231
        assert page.photometric == PHOTOMETRIC.MINISBLACK
6232
        assert not page.is_contiguous
6233
        assert page.compression == COMPRESSION.NONE
6234
        assert page.imagewidth == 128
6235
        assert page.imagelength == 128
6236
        assert page.bitspersample == 4
6237
        assert page.samplesperpixel == 1
6238
        # assert series properties
6239
        series = tif.series[0]
6240
        assert series.shape == (128, 128)
6241
        assert series.dtype == numpy.uint8
6242
        assert series.axes == 'YX'
6243
        assert series.kind == 'uniform'
6244
        assert series.dataoffset is None
6245
        # assert data
6246
        data = tif.asarray()
6247
        assert isinstance(data, numpy.ndarray)
6248
        assert data.shape == (128, 128)
6249
        assert data[50, 63] == 13
6250
    # reversed
6251
    fname = public_file('pillow/tiff_gray_2_4_bpp/hopper4R.tif')
6252
    with TiffFile(fname) as tif:
6253
        page = tif.pages.first
6254
        assert page.photometric == PHOTOMETRIC.MINISBLACK
6255
        assert page.fillorder == FILLORDER.LSB2MSB
6256
        assert_array_equal(tif.asarray(), data)
6257
        assert__str__(tif)
6258
    # inverted
6259
    fname = public_file('pillow/tiff_gray_2_4_bpp/hopper4I.tif')
6260
    with TiffFile(fname) as tif:
6261
        page = tif.pages.first
6262
        assert page.photometric == PHOTOMETRIC.MINISWHITE
6263
        assert_array_equal(tif.asarray(), 15 - data)
6264
        assert__str__(tif)
6265
    # inverted and reversed
6266
    fname = public_file('pillow/tiff_gray_2_4_bpp/hopper4IR.tif')
6267
    with TiffFile(fname) as tif:
6268
        page = tif.pages.first
6269
        assert page.photometric == PHOTOMETRIC.MINISWHITE
6270
        assert_array_equal(tif.asarray(), 15 - data)
6271
        assert__str__(tif)
6272

6273

6274
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
6275
def test_read_lsb2msb():
6276
    """Test read fillorder=lsb2msb, 2 series."""
6277
    # http://lists.openmicroscopy.org.uk/pipermail/ome-users
6278
    #   /2015-September/005635.html
6279
    fname = private_file('test_lsb2msb.tif')
6280
    with TiffFile(fname) as tif:
6281
        assert tif.byteorder == '<'
6282
        assert len(tif.pages) == 2
6283
        assert len(tif.series) == 2
6284
        # assert page properties
6285
        page = tif.pages.first
6286
        assert page.is_contiguous
6287
        assert page.compression == COMPRESSION.NONE
6288
        assert page.imagewidth == 7100
6289
        assert page.imagelength == 4700
6290
        assert page.bitspersample == 16
6291
        assert page.samplesperpixel == 3
6292
        page = tif.pages[1]
6293
        assert page.is_contiguous
6294
        assert page.compression == COMPRESSION.NONE
6295
        assert page.imagewidth == 7100
6296
        assert page.imagelength == 4700
6297
        assert page.bitspersample == 16
6298
        assert page.samplesperpixel == 1
6299
        # assert series properties
6300
        series = tif.series[0]
6301
        assert series.shape == (4700, 7100, 3)
6302
        assert series.dtype == numpy.uint16
6303
        assert series.axes == 'YXS'
6304
        assert series.dataoffset is None
6305
        series = tif.series[1]
6306
        assert series.shape == (4700, 7100)
6307
        assert series.dtype == numpy.uint16
6308
        assert series.axes == 'YX'
6309
        assert series.kind == 'generic'
6310
        assert series.dataoffset is None
6311
        # assert data
6312
        data = tif.asarray(series=0)
6313
        assert isinstance(data, numpy.ndarray)
6314
        assert data.shape == (4700, 7100, 3)
6315
        assert data[2350, 3550, 1] == 60457
6316
        assert_aszarr_method(tif, data, series=0)
6317
        data = tif.asarray(series=1)
6318
        assert isinstance(data, numpy.ndarray)
6319
        assert data.flags['C_CONTIGUOUS']
6320
        assert data.shape == (4700, 7100)
6321
        assert data[2350, 3550] == 56341
6322
        assert_aszarr_method(tif, data, series=1)
6323
        assert__str__(tif)
6324

6325

6326
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
6327
def test_read_gimp_u2():
6328
    """Test read uint16 with horizontal predictor by GIMP."""
6329
    fname = public_file('tifffile/gimp_u2.tiff')
6330
    with TiffFile(fname) as tif:
6331
        assert len(tif.pages) == 1
6332
        page = tif.pages.first
6333
        assert page.compression == COMPRESSION.ADOBE_DEFLATE
6334
        assert page.photometric == PHOTOMETRIC.RGB
6335
        assert page.predictor == PREDICTOR.HORIZONTAL
6336
        assert page.imagewidth == 333
6337
        assert page.imagelength == 231
6338
        assert page.samplesperpixel == 3
6339
        image = tif.asarray()
6340
        assert image.flags['C_CONTIGUOUS']
6341
        assert tuple(image[110, 110]) == (23308, 17303, 41160)
6342
        assert_aszarr_method(tif, image)
6343
        assert__str__(tif)
6344

6345

6346
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
6347
def test_read_gimp_f4():
6348
    """Test read float32 with horizontal predictor by GIMP."""
6349
    fname = public_file('tifffile/gimp_f4.tiff')
6350
    with TiffFile(fname) as tif:
6351
        assert len(tif.pages) == 1
6352
        page = tif.pages.first
6353
        assert page.compression == COMPRESSION.ADOBE_DEFLATE
6354
        assert page.photometric == PHOTOMETRIC.RGB
6355
        assert page.predictor == PREDICTOR.HORIZONTAL
6356
        assert page.imagewidth == 333
6357
        assert page.imagelength == 231
6358
        assert page.samplesperpixel == 3
6359
        image = tif.asarray()
6360
        assert image.flags['C_CONTIGUOUS']
6361
        assert_array_almost_equal(
6362
            image[110, 110], (0.35565534, 0.26402164, 0.6280674)
6363
        )
6364
        assert_aszarr_method(tif, image)
6365
        assert__str__(tif)
6366

6367

6368
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
6369
def test_read_gimp_f2():
6370
    """Test read float16 with horizontal predictor by GIMP."""
6371
    fname = public_file('tifffile/gimp_f2.tiff')
6372
    with TiffFile(fname) as tif:
6373
        assert len(tif.pages) == 1
6374
        page = tif.pages.first
6375
        assert page.compression == COMPRESSION.ADOBE_DEFLATE
6376
        assert page.photometric == PHOTOMETRIC.RGB
6377
        assert page.predictor == PREDICTOR.HORIZONTAL
6378
        assert page.imagewidth == 333
6379
        assert page.imagelength == 231
6380
        assert page.samplesperpixel == 3
6381
        image = tif.asarray()
6382
        assert image.flags['C_CONTIGUOUS']
6383
        assert_array_almost_equal(
6384
            image[110, 110].astype(numpy.float64),
6385
            (0.35571289, 0.26391602, 0.62792969),
6386
        )
6387
        assert_aszarr_method(tif, image)
6388
        assert__str__(tif)
6389

6390

6391
@pytest.mark.skipif(
6392
    SKIP_PRIVATE or SKIP_CODECS or not imagecodecs.JPEG8.available,
6393
    reason=REASON,
6394
)
6395
def test_read_dng_jpeglossy():
6396
    """Test read JPEG_LOSSY in DNG."""
6397
    fname = private_file('DNG/Adobe DNG Converter.dng')
6398
    with TiffFile(fname) as tif:
6399
        assert len(tif.pages) == 1
6400
        assert len(tif.series) == 6
6401
        for series in tif.series:
6402
            image = series.asarray()
6403
            assert_aszarr_method(series, image)
6404
        assert__str__(tif)
6405

6406

6407
@pytest.mark.skipif(
6408
    SKIP_PRIVATE or SKIP_CODECS or not imagecodecs.LJPEG.available,
6409
    reason=REASON,
6410
)
6411
def test_read_dng_ljpeg():
6412
    """Test read 14-bit CFA LJPEG in DNG."""
6413
    fname = private_file('DNG/uint14_ljpeg_cfa.dng')
6414
    with TiffFile(fname) as tif:
6415
        assert len(tif.pages) == 1
6416
        assert len(tif.series) == 3
6417
        page = tif.pages.first.pages[0]
6418
        assert page.compression == COMPRESSION.JPEG
6419
        assert page.photometric == PHOTOMETRIC.CFA
6420
        assert page.imagewidth == 7392
6421
        assert page.imagelength == 4950
6422
        assert page.bitspersample == 14
6423
        assert page.samplesperpixel == 1
6424
        assert page.tags['CFARepeatPatternDim'].value == (2, 2)
6425
        assert page.tags['CFAPattern'].value == b'\0\1\1\2'
6426
        assert page.tags['CFALayout'].value == 1
6427
        image = page.asarray()
6428
        assert image.shape == (4950, 7392)
6429
        assert image.dtype == numpy.uint16
6430
        assert image[1024, 1024] == 3425
6431
        assert__str__(tif)
6432

6433

6434
@pytest.mark.skipif(
6435
    SKIP_PRIVATE or SKIP_CODECS or not imagecodecs.LJPEG.available,
6436
    reason=REASON,
6437
)
6438
def test_read_dng_linearraw():
6439
    """Test read 12-bit LinearRAW LJPEG in DNG."""
6440
    fname = private_file('DNG/LinearRaw.dng')
6441
    with TiffFile(fname) as tif:
6442
        assert len(tif.pages) == 1
6443
        assert len(tif.series) == 2
6444
        page = tif.pages.first.pages[0]
6445
        assert page.compression == COMPRESSION.JPEG
6446
        assert page.photometric == PHOTOMETRIC.LINEAR_RAW
6447
        assert page.imagewidth == 4032
6448
        assert page.imagelength == 3024
6449
        assert page.bitspersample == 12
6450
        assert page.samplesperpixel == 3
6451
        assert page.tile == (378, 504)
6452
        image = page.asarray()
6453
        assert image.shape == (3024, 4032, 3)
6454
        assert image.dtype == numpy.uint16
6455
        assert tuple(image[740, 3660]) == (1474, 3090, 1655)
6456
        assert__str__(tif)
6457

6458

6459
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
6460
@pytest.mark.parametrize('fp', ['fp16', 'fp24', 'fp32'])
6461
def test_read_dng_floatpredx2(fp):
6462
    """Test read FLOATINGPOINTX2 predictor in DNG."""
6463
    # <https://raw.pixls.us/data/Canon/EOS%205D%20Mark%20III/>
6464
    fname = private_file(f'DNG/fpx2/hdrmerge-bayer-{fp}-w-pred-deflate.dng')
6465
    with TiffFile(fname) as tif:
6466
        assert len(tif.pages) == 1
6467
        assert len(tif.series) == 3
6468
        page = tif.pages.first.pages[0]
6469
        assert page.compression == COMPRESSION.ADOBE_DEFLATE
6470
        assert page.photometric == PHOTOMETRIC.CFA
6471
        assert page.predictor == 34894
6472
        assert page.imagewidth == 5920
6473
        assert page.imagelength == 3950
6474
        assert page.sampleformat == SAMPLEFORMAT.IEEEFP
6475
        assert page.bitspersample == int(fp[2:])
6476
        assert page.samplesperpixel == 1
6477
        if fp == 'fp24':
6478
            with pytest.raises(NotImplementedError):
6479
                image = page.asarray()
6480
        else:
6481
            image = page.asarray()
6482
            assert_aszarr_method(page, image)
6483
        assert__str__(tif)
6484

6485

6486
@pytest.mark.skipif(
6487
    SKIP_PRIVATE or SKIP_CODECS or not imagecodecs.JPEGXL.available,
6488
    reason=REASON,
6489
)
6490
def test_read_dng_jpegxl():
6491
    """Test read JPEGXL in DNG."""
6492
    fname = private_file('DNG/20240125_204051_1.dng')
6493
    with TiffFile(fname) as tif:
6494
        assert len(tif.pages) == 1
6495
        assert len(tif.series) == 6
6496

6497
        page = tif.pages.first.pages[0]
6498
        assert not page.is_reduced
6499
        assert page.compression == COMPRESSION.JPEGXL_DNG
6500
        assert page.photometric == PHOTOMETRIC.LINEAR_RAW
6501
        assert page.imagewidth == 5712
6502
        assert page.imagelength == 4284
6503
        assert page.bitspersample == 16
6504
        assert page.samplesperpixel == 3
6505
        image = page.asarray()
6506
        assert image.shape == (4284, 5712, 3)
6507
        assert image.dtype == numpy.uint16
6508
        assert image[1024, 1024, 1] == 36
6509

6510
        page = tif.pages.first.pages[1]
6511
        assert page.is_reduced
6512
        assert page.compression == COMPRESSION.JPEGXL_DNG
6513
        assert page.photometric == PHOTOMETRIC.RGB
6514
        assert page.imagewidth == 1024
6515
        assert page.imagelength == 768
6516
        assert page.bitspersample == 8
6517
        assert page.samplesperpixel == 3
6518
        image = page.asarray()
6519
        assert image.shape == (768, 1024, 3)
6520
        assert image.dtype == numpy.uint8
6521
        assert image[512, 512, 1] in {47, 48}
6522
        assert page.tags['JXLDistance'].value == 2.0
6523
        assert page.tags['JXLEffort'].value == 7
6524
        assert page.tags['JXLDecodeSpeed'].value == 4
6525
        assert__str__(tif)
6526

6527

6528
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
6529
@pytest.mark.parametrize('fname', ['sample1.orf', 'sample1.rw2'])
6530
def test_read_rawformats(fname, caplog):
6531
    """Test parse unsupported RAW formats."""
6532
    fname = private_file(f'RAWformats/{fname}')
6533
    with TiffFile(fname) as tif:
6534
        assert 'RAW format' in caplog.text
6535
        assert__str__(tif)
6536

6537

6538
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
6539
def test_read_iss_vista():
6540
    """Test read bogus imagedepth tag by ISS Vista."""
6541
    fname = private_file('iss/10um_beads_14stacks_ch1.tif')
6542
    with TiffFile(fname) as tif:
6543
        assert tif.byteorder == '<'
6544
        assert len(tif.pages) == 14
6545
        assert len(tif.series) == 1
6546
        # assert page properties
6547
        page = tif.pages.first
6548
        assert not page.is_reduced
6549
        assert not page.is_tiled
6550
        assert page.compression == COMPRESSION.NONE
6551
        assert page.imagewidth == 256
6552
        assert page.imagelength == 256
6553
        assert page.tags['ImageDepth'].value == 14  # bogus
6554
        assert page.bitspersample == 16
6555
        assert page.samplesperpixel == 1
6556
        # assert series properties
6557
        series = tif.series[0]
6558
        assert series.shape == (14, 256, 256)
6559
        assert series.dtype == numpy.int16
6560
        assert series.axes == 'IYX'  # ZYX
6561
        assert series.kind == 'uniform'
6562
        assert isinstance(series.pages[3], TiffFrame)
6563
        assert_aszarr_method(series)
6564
        assert__str__(tif)
6565

6566

6567
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
6568
def test_read_vips():
6569
    """Test read 347x641 RGB, bigtiff, pyramid, tiled, produced by VIPS."""
6570
    fname = private_file('vips.tif')
6571
    with TiffFile(fname) as tif:
6572
        assert tif.byteorder == '<'
6573
        assert len(tif.pages) == 4
6574
        assert len(tif.series) == 1
6575
        # assert page properties
6576
        page = tif.pages.first
6577
        assert not page.is_reduced
6578
        assert page.is_tiled
6579
        assert page.compression == COMPRESSION.ADOBE_DEFLATE
6580
        assert page.imagewidth == 641
6581
        assert page.imagelength == 347
6582
        assert page.bitspersample == 8
6583
        assert page.samplesperpixel == 3
6584
        # assert series properties
6585
        series = tif.series[0]
6586
        assert series.is_pyramidal
6587
        assert len(series.levels) == 4
6588
        assert series.shape == (347, 641, 3)
6589
        assert series.dtype == numpy.uint8
6590
        assert series.axes == 'YXS'
6591
        assert series.kind == 'generic'
6592
        # level 3
6593
        series = series.levels[3]
6594
        page = series.pages[0]
6595
        assert page.is_reduced
6596
        assert page.is_tiled
6597
        assert series.shape == (43, 80, 3)
6598
        assert series.dtype == numpy.uint8
6599
        assert series.axes == 'YXS'
6600
        # assert data
6601
        data = tif.asarray(series=0)
6602
        assert isinstance(data, numpy.ndarray)
6603
        assert data.flags['C_CONTIGUOUS']
6604
        assert data.shape == (347, 641, 3)
6605
        assert data.dtype == numpy.uint8
6606
        assert tuple(data[132, 361]) == (114, 233, 58)
6607
        assert_aszarr_method(tif, data, series=0, level=0)
6608
        assert__str__(tif)
6609

6610

6611
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
6612
def test_read_volumetric():
6613
    """Test read 128x128x128, float32, tiled SGI."""
6614
    fname = public_file('tifffile/sgi_depth.tif')
6615
    with TiffFile(fname) as tif:
6616
        assert tif.byteorder == '<'
6617
        assert len(tif.pages) == 1
6618
        assert len(tif.series) == 1
6619
        # assert page properties
6620
        page = tif.pages.first
6621
        assert page.is_volumetric
6622
        assert page.planarconfig == PLANARCONFIG.CONTIG
6623
        assert page.is_tiled
6624
        assert page.is_contiguous
6625
        assert page.compression == COMPRESSION.NONE
6626
        assert page.imagewidth == 128
6627
        assert page.imagelength == 128
6628
        assert page.imagedepth == 128
6629
        assert page.tilewidth == 128
6630
        assert page.tilelength == 128
6631
        assert page.tiledepth == 1
6632
        assert page.tile == (128, 128)
6633
        assert page.bitspersample == 32
6634
        assert page.samplesperpixel == 1
6635
        assert page.tags['Software'].value == (
6636
            'MFL MeVis File Format Library, TIFF Module'
6637
        )
6638
        # assert series properties
6639
        series = tif.series[0]
6640
        assert series.shape == (128, 128, 128)
6641
        assert series.dtype == numpy.float32
6642
        assert series.axes == 'ZYX'
6643
        assert series.kind == 'uniform'
6644
        # assert data
6645
        data = tif.asarray()
6646
        assert isinstance(data, numpy.ndarray)
6647
        assert data.flags['C_CONTIGUOUS']
6648
        assert data.shape == (128, 128, 128)
6649
        assert data.dtype == numpy.float32
6650
        assert data[64, 64, 64] == 0.0
6651
        assert_decode_method(page)
6652
        assert_aszarr_method(tif, data)
6653
        assert__str__(tif)
6654

6655

6656
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_CODECS, reason=REASON)
6657
def test_read_oxford():
6658
    """Test read 601x81, uint8, LZW."""
6659
    fname = public_file('juicypixels/oxford.tif')
6660
    with TiffFile(fname) as tif:
6661
        assert tif.byteorder == '>'
6662
        assert len(tif.pages) == 1
6663
        assert len(tif.series) == 1
6664
        # assert page properties
6665
        page = tif.pages.first
6666
        assert page.planarconfig == PLANARCONFIG.SEPARATE
6667
        assert page.photometric == PHOTOMETRIC.RGB
6668
        assert page.compression == COMPRESSION.LZW
6669
        assert page.imagewidth == 601
6670
        assert page.imagelength == 81
6671
        assert page.bitspersample == 8
6672
        assert page.samplesperpixel == 3
6673
        # assert series properties
6674
        series = tif.series[0]
6675
        assert series.shape == (3, 81, 601)
6676
        assert series.dtype == numpy.uint8
6677
        assert series.axes == 'SYX'
6678
        assert series.kind == 'uniform'
6679
        # assert data
6680
        data = tif.asarray()
6681
        assert isinstance(data, numpy.ndarray)
6682
        assert data.flags['C_CONTIGUOUS']
6683
        assert data.shape == (3, 81, 601)
6684
        assert data.dtype == numpy.uint8
6685
        assert data[1, 24, 49] == 191
6686
        assert_aszarr_method(tif, data)
6687
        assert__str__(tif)
6688

6689

6690
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
6691
def test_read_cramps():
6692
    """Test 800x607 uint8, PackBits."""
6693
    fname = public_file('juicypixels/cramps.tif')
6694
    with TiffFile(fname) as tif:
6695
        assert tif.byteorder == '>'
6696
        assert len(tif.pages) == 1
6697
        assert len(tif.series) == 1
6698
        # assert page properties
6699
        page = tif.pages.first
6700
        assert page.compression == COMPRESSION.PACKBITS
6701
        assert page.photometric == PHOTOMETRIC.MINISWHITE
6702
        assert page.imagewidth == 800
6703
        assert page.imagelength == 607
6704
        assert page.bitspersample == 8
6705
        assert page.samplesperpixel == 1
6706
        # assert series properties
6707
        series = tif.series[0]
6708
        assert series.shape == (607, 800)
6709
        assert series.dtype == numpy.uint8
6710
        assert series.axes == 'YX'
6711
        assert series.kind == 'uniform'
6712
        # assert data
6713
        data = tif.asarray()
6714
        assert isinstance(data, numpy.ndarray)
6715
        assert data.flags['C_CONTIGUOUS']
6716
        assert data.shape == (607, 800)
6717
        assert data.dtype == numpy.uint8
6718
        assert data[273, 426] == 34
6719
        assert_aszarr_method(tif, data)
6720
        assert__str__(tif)
6721

6722

6723
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
6724
def test_read_cramps_tile():
6725
    """Test read 800x607 uint8, raw, volumetric, tiled."""
6726
    fname = public_file('juicypixels/cramps-tile.tif')
6727
    with TiffFile(fname) as tif:
6728
        assert tif.byteorder == '>'
6729
        assert len(tif.pages) == 1
6730
        assert len(tif.series) == 1
6731
        # assert page properties
6732
        page = tif.pages.first
6733
        assert page.is_tiled
6734
        assert not page.is_volumetric
6735
        assert page.compression == COMPRESSION.NONE
6736
        assert page.photometric == PHOTOMETRIC.MINISWHITE
6737
        assert page.imagewidth == 800
6738
        assert page.imagelength == 607
6739
        assert page.imagedepth == 1
6740
        assert page.tilewidth == 256
6741
        assert page.tilelength == 256
6742
        assert page.tiledepth == 1
6743
        assert page.bitspersample == 8
6744
        assert page.samplesperpixel == 1
6745
        # assert series properties
6746
        series = tif.series[0]
6747
        assert series.shape == (607, 800)
6748
        assert series.dtype == numpy.uint8
6749
        assert series.axes == 'YX'
6750
        assert series.kind == 'uniform'
6751
        # assert data
6752
        data = tif.asarray()
6753
        assert isinstance(data, numpy.ndarray)
6754
        assert data.flags['C_CONTIGUOUS']
6755
        assert data.shape == (607, 800)
6756
        assert data.dtype == numpy.uint8
6757
        assert data[273, 426] == 34
6758
        assert_aszarr_method(tif, data)
6759
        assert__str__(tif)
6760

6761

6762
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
6763
def test_read_jello():
6764
    """Test read 256x192x3, uint16, palette, PackBits."""
6765
    fname = public_file('juicypixels/jello.tif')
6766
    with TiffFile(fname) as tif:
6767
        assert tif.byteorder == '>'
6768
        assert len(tif.pages) == 1
6769
        assert len(tif.series) == 1
6770
        # assert page properties
6771
        page = tif.pages.first
6772
        assert page.photometric == PHOTOMETRIC.PALETTE
6773
        assert page.planarconfig == PLANARCONFIG.CONTIG
6774
        assert page.compression == COMPRESSION.PACKBITS
6775
        assert page.imagewidth == 256
6776
        assert page.imagelength == 192
6777
        assert page.bitspersample == 8
6778
        assert page.samplesperpixel == 1
6779
        # assert series properties
6780
        series = tif.series[0]
6781
        assert series.shape == (192, 256)
6782
        assert series.dtype == numpy.uint8
6783
        assert series.axes == 'YX'
6784
        assert series.kind == 'uniform'
6785
        # assert data
6786
        data = page.asrgb(uint8=False)
6787
        assert isinstance(data, numpy.ndarray)
6788
        assert data.flags['C_CONTIGUOUS']
6789
        assert data.shape == (192, 256, 3)
6790
        assert data.dtype == numpy.uint16
6791
        assert tuple(data[100, 140, :]) == (48895, 65279, 48895)
6792
        assert__str__(tif)
6793

6794

6795
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_CODECS, reason=REASON)
6796
def test_read_quad_lzw():
6797
    """Test read 384x512 RGB uint8 old style LZW."""
6798
    fname = public_file('libtiff/quad-lzw-compat.tiff')
6799
    with TiffFile(fname) as tif:
6800
        assert tif.byteorder == '>'
6801
        assert len(tif.pages) == 1
6802
        assert len(tif.series) == 1
6803
        # assert page properties
6804
        page = tif.pages.first
6805
        assert not page.is_tiled
6806
        assert page.photometric == PHOTOMETRIC.RGB
6807
        assert page.compression == COMPRESSION.LZW
6808
        assert page.imagewidth == 512
6809
        assert page.imagelength == 384
6810
        assert page.bitspersample == 8
6811
        assert page.samplesperpixel == 3
6812
        # assert series properties
6813
        series = tif.series[0]
6814
        assert series.shape == (384, 512, 3)
6815
        assert series.dtype == numpy.uint8
6816
        assert series.axes == 'YXS'
6817
        assert series.kind == 'uniform'
6818
        # assert data
6819
        data = tif.asarray()
6820
        assert isinstance(data, numpy.ndarray)
6821
        assert data.flags['C_CONTIGUOUS']
6822
        assert data.shape == (384, 512, 3)
6823
        assert data.dtype == numpy.uint8
6824
        assert tuple(data[309, 460, :]) == (0, 163, 187)
6825
        assert_aszarr_method(tif, data)
6826

6827

6828
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
6829
def test_read_quad_lzw_le():
6830
    """Test read 384x512 RGB uint8 LZW."""
6831
    fname = private_file('quad-lzw_le.tif')
6832
    with TiffFile(fname) as tif:
6833
        assert tif.byteorder == '<'
6834
        assert len(tif.pages) == 1
6835
        assert len(tif.series) == 1
6836
        # assert page properties
6837
        page = tif.pages.first
6838
        assert page.photometric == PHOTOMETRIC.RGB
6839
        assert not page.is_tiled
6840
        assert page.compression == COMPRESSION.LZW
6841
        assert page.imagewidth == 512
6842
        assert page.imagelength == 384
6843
        assert page.bitspersample == 8
6844
        assert page.samplesperpixel == 3
6845
        # assert series properties
6846
        series = tif.series[0]
6847
        assert series.shape == (384, 512, 3)
6848
        assert series.dtype == numpy.uint8
6849
        assert series.axes == 'YXS'
6850
        assert series.kind == 'uniform'
6851
        # assert data
6852
        data = tif.asarray()
6853
        assert isinstance(data, numpy.ndarray)
6854
        assert data.flags['C_CONTIGUOUS']
6855
        assert data.shape == (384, 512, 3)
6856
        assert data.dtype == numpy.uint8
6857
        assert tuple(data[309, 460, :]) == (0, 163, 187)
6858
        assert_aszarr_method(tif, data)
6859
        assert_decode_method(page)
6860

6861

6862
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_CODECS, reason=REASON)
6863
def test_read_quad_tile():
6864
    """Test read 384x512 RGB uint8 LZW tiled."""
6865
    # Strips and tiles defined in same page
6866
    fname = public_file('juicypixels/quad-tile.tif')
6867
    with TiffFile(fname) as tif:
6868
        assert__str__(tif)
6869
        assert tif.byteorder == '>'
6870
        assert len(tif.pages) == 1
6871
        assert len(tif.series) == 1
6872
        # assert page properties
6873
        page = tif.pages.first
6874
        assert page.photometric == PHOTOMETRIC.RGB
6875
        assert page.is_tiled
6876
        assert page.compression == COMPRESSION.LZW
6877
        assert page.imagewidth == 512
6878
        assert page.imagelength == 384
6879
        assert page.imagedepth == 1
6880
        assert page.tilewidth == 128
6881
        assert page.tilelength == 128
6882
        assert page.tiledepth == 1
6883
        assert page.bitspersample == 8
6884
        assert page.samplesperpixel == 3
6885
        # assert series properties
6886
        series = tif.series[0]
6887
        assert series.shape == (384, 512, 3)
6888
        assert series.dtype == numpy.uint8
6889
        assert series.axes == 'YXS'
6890
        assert series.kind == 'uniform'
6891
        # assert data
6892
        data = tif.asarray()
6893
        # assert 'invalid tile data (49153,) (1, 128, 128, 3)' in caplog.text
6894
        assert isinstance(data, numpy.ndarray)
6895
        assert data.flags['C_CONTIGUOUS']
6896
        assert data.shape == (384, 512, 3)
6897
        assert data.dtype == numpy.uint8
6898
        assert tuple(data[309, 460, :]) == (0, 163, 187)
6899
        assert_aszarr_method(tif, data)
6900

6901

6902
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_CODECS, reason=REASON)
6903
def test_read_strike():
6904
    """Test read 256x200 RGBA uint8 LZW."""
6905
    fname = public_file('juicypixels/strike.tif')
6906
    with TiffFile(fname) as tif:
6907
        assert__str__(tif)
6908
        assert tif.byteorder == '>'
6909
        assert len(tif.pages) == 1
6910
        assert len(tif.series) == 1
6911
        # assert page properties
6912
        page = tif.pages.first
6913
        assert page.photometric == PHOTOMETRIC.RGB
6914
        assert page.compression == COMPRESSION.LZW
6915
        assert page.imagewidth == 256
6916
        assert page.imagelength == 200
6917
        assert page.bitspersample == 8
6918
        assert page.samplesperpixel == 4
6919
        assert page.extrasamples[0] == EXTRASAMPLE.ASSOCALPHA
6920
        # assert series properties
6921
        series = tif.series[0]
6922
        assert series.shape == (200, 256, 4)
6923
        assert series.dtype == numpy.uint8
6924
        assert series.axes == 'YXS'
6925
        assert series.kind == 'uniform'
6926
        # assert data
6927
        data = tif.asarray()
6928
        assert isinstance(data, numpy.ndarray)
6929
        assert data.flags['C_CONTIGUOUS']
6930
        assert data.shape == (200, 256, 4)
6931
        assert data.dtype == numpy.uint8
6932
        assert tuple(data[65, 139, :]) == (43, 34, 17, 91)
6933
        assert_aszarr_method(tif, data)
6934
        assert_decode_method(page)
6935
        assert__str__(tif)
6936

6937

6938
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
6939
def test_read_incomplete_tile_contig():
6940
    """Test read PackBits compressed incomplete tile, contig RGB."""
6941
    fname = public_file('GDAL/contig_tiled.tif')
6942
    with TiffFile(fname) as tif:
6943
        assert tif.byteorder == '>'
6944
        assert len(tif.pages) == 1
6945
        assert len(tif.series) == 1
6946
        # assert page properties
6947
        page = tif.pages.first
6948
        assert page.photometric == PHOTOMETRIC.RGB
6949
        assert page.planarconfig == PLANARCONFIG.CONTIG
6950
        assert page.compression == COMPRESSION.PACKBITS
6951
        assert page.imagewidth == 35
6952
        assert page.imagelength == 37
6953
        assert page.bitspersample == 8
6954
        assert page.samplesperpixel == 3
6955
        # assert series properties
6956
        series = tif.series[0]
6957
        assert series.shape == (37, 35, 3)
6958
        assert series.dtype == numpy.uint8
6959
        assert series.axes == 'YXS'
6960
        assert series.kind == 'uniform'
6961
        # assert data
6962
        data = page.asarray()
6963
        assert data.flags['C_CONTIGUOUS']
6964
        assert data.shape == (37, 35, 3)
6965
        assert data.dtype == numpy.uint8
6966
        assert tuple(data[19, 31]) == (50, 50, 50)
6967
        assert tuple(data[36, 34]) == (70, 70, 70)
6968
        assert_aszarr_method(page, data)
6969
        assert_decode_method(page)
6970
        assert__str__(tif)
6971

6972

6973
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
6974
def test_read_incomplete_tile_separate():
6975
    """Test read PackBits compressed incomplete tile, separate RGB."""
6976
    fname = public_file('GDAL/separate_tiled.tif')
6977
    with TiffFile(fname) as tif:
6978
        assert tif.byteorder == '>'
6979
        assert len(tif.pages) == 1
6980
        assert len(tif.series) == 1
6981
        # assert page properties
6982
        page = tif.pages.first
6983
        assert page.photometric == PHOTOMETRIC.RGB
6984
        assert page.planarconfig == PLANARCONFIG.SEPARATE
6985
        assert page.compression == COMPRESSION.PACKBITS
6986
        assert page.imagewidth == 35
6987
        assert page.imagelength == 37
6988
        assert page.bitspersample == 8
6989
        assert page.samplesperpixel == 3
6990
        # assert series properties
6991
        series = tif.series[0]
6992
        assert series.shape == (3, 37, 35)
6993
        assert series.dtype == numpy.uint8
6994
        assert series.axes == 'SYX'
6995
        assert series.kind == 'uniform'
6996
        # assert data
6997
        data = page.asarray()
6998
        assert data.flags['C_CONTIGUOUS']
6999
        assert data.shape == (3, 37, 35)
7000
        assert data.dtype == numpy.uint8
7001
        assert tuple(data[:, 19, 31]) == (50, 50, 50)
7002
        assert tuple(data[:, 36, 34]) == (70, 70, 70)
7003
        assert_aszarr_method(page, data)
7004
        assert_decode_method(page)
7005
        assert__str__(tif)
7006

7007

7008
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
7009
def test_read_django():
7010
    """Test read 3x480x320, uint16, palette, raw."""
7011
    fname = private_file('django.tiff')
7012
    with TiffFile(fname) as tif:
7013
        assert tif.byteorder == '<'
7014
        assert len(tif.pages) == 1
7015
        assert len(tif.series) == 1
7016
        # assert page properties
7017
        page = tif.pages.first
7018
        assert page.photometric == PHOTOMETRIC.PALETTE
7019
        assert page.planarconfig == PLANARCONFIG.CONTIG
7020
        assert page.compression == COMPRESSION.NONE
7021
        assert page.imagewidth == 320
7022
        assert page.imagelength == 480
7023
        assert page.bitspersample == 8
7024
        assert page.samplesperpixel == 1
7025
        # assert series properties
7026
        series = tif.series[0]
7027
        assert series.shape == (480, 320)
7028
        assert series.dtype == numpy.uint8
7029
        assert series.axes == 'YX'
7030
        assert series.kind == 'uniform'
7031
        # assert data
7032
        data = page.asrgb(uint8=False)
7033
        assert isinstance(data, numpy.ndarray)
7034
        assert data.flags['C_CONTIGUOUS']
7035
        assert data.shape == (480, 320, 3)
7036
        assert data.dtype == numpy.uint16
7037
        assert tuple(data[64, 64, :]) == (65535, 52171, 63222)
7038
        assert__str__(tif)
7039

7040

7041
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
7042
def test_read_pygame_icon():
7043
    """Test read 128x128 RGBA uint8 PackBits."""
7044
    fname = private_file('pygame_icon.tiff')
7045
    with TiffFile(fname) as tif:
7046
        assert tif.byteorder == '>'
7047
        assert len(tif.pages) == 1
7048
        assert len(tif.series) == 1
7049
        # assert page properties
7050
        page = tif.pages.first
7051
        assert page.photometric == PHOTOMETRIC.RGB
7052
        assert page.compression == COMPRESSION.PACKBITS
7053
        assert page.imagewidth == 128
7054
        assert page.imagelength == 128
7055
        assert page.bitspersample == 8
7056
        assert page.samplesperpixel == 4
7057
        assert page.extrasamples[0] == EXTRASAMPLE.UNASSALPHA  # ?
7058
        assert page.tags['Software'].value == 'QuickTime 5.0.5'
7059
        assert page.tags['HostComputer'].value == 'MacOS 10.1.2'
7060
        assert page.tags['DateTime'].value == '2001:12:21 04:34:56'
7061
        assert page.datetime == datetime.datetime(2001, 12, 21, 4, 34, 56)
7062
        # assert series properties
7063
        series = tif.series[0]
7064
        assert series.shape == (128, 128, 4)
7065
        assert series.dtype == numpy.uint8
7066
        assert series.axes == 'YXS'
7067
        assert series.kind == 'uniform'
7068
        # assert data
7069
        data = tif.asarray()
7070
        assert isinstance(data, numpy.ndarray)
7071
        assert data.flags['C_CONTIGUOUS']
7072
        assert data.shape == (128, 128, 4)
7073
        assert data.dtype == numpy.uint8
7074
        assert tuple(data[22, 112, :]) == (100, 99, 98, 132)
7075
        assert_aszarr_method(tif, data)
7076
        assert__str__(tif)
7077

7078

7079
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
7080
def test_read_rgba_wo_extra_samples():
7081
    """Test read 1065x785 RGBA uint8."""
7082
    fname = private_file('rgba_wo_extra_samples.tif')
7083
    with TiffFile(fname) as tif:
7084
        assert tif.byteorder == '<'
7085
        assert len(tif.pages) == 1
7086
        assert len(tif.series) == 1
7087
        # assert page properties
7088
        page = tif.pages.first
7089
        assert page.photometric == PHOTOMETRIC.RGB
7090
        assert page.compression == COMPRESSION.LZW
7091
        assert page.imagewidth == 1065
7092
        assert page.imagelength == 785
7093
        assert page.bitspersample == 8
7094
        assert page.samplesperpixel == 4
7095
        # with self.assertRaises(AttributeError):
7096
        #     page.extrasamples
7097
        # assert series properties
7098
        series = tif.series[0]
7099
        assert series.shape == (785, 1065, 4)
7100
        assert series.dtype == numpy.uint8
7101
        assert series.axes == 'YXS'
7102
        assert series.kind == 'uniform'
7103
        # assert data
7104
        data = tif.asarray()
7105
        assert isinstance(data, numpy.ndarray)
7106
        assert data.flags['C_CONTIGUOUS']
7107
        assert data.shape == (785, 1065, 4)
7108
        assert data.dtype == numpy.uint8
7109
        assert tuple(data[560, 412, :]) == (60, 92, 74, 255)
7110
        assert_aszarr_method(tif, data)
7111
        assert_decode_method(page)
7112
        assert__str__(tif)
7113

7114

7115
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
7116
def test_read_rgb565():
7117
    """Test read 64x64 RGB uint8 5,6,5 bitspersample."""
7118
    fname = private_file('rgb565.tif')
7119
    with TiffFile(fname) as tif:
7120
        assert tif.byteorder == '<'
7121
        assert len(tif.pages) == 1
7122
        assert len(tif.series) == 1
7123
        # assert page properties
7124
        page = tif.pages.first
7125
        assert page.photometric == PHOTOMETRIC.RGB
7126
        assert page.compression == COMPRESSION.NONE
7127
        assert page.imagewidth == 64
7128
        assert page.imagelength == 64
7129
        assert page.bitspersample == (5, 6, 5)
7130
        assert page.samplesperpixel == 3
7131
        # assert series properties
7132
        series = tif.series[0]
7133
        assert series.shape == (64, 64, 3)
7134
        assert series.dtype == numpy.uint8
7135
        assert series.axes == 'YXS'
7136
        assert series.kind == 'uniform'
7137
        # assert data
7138
        data = tif.asarray()
7139
        assert isinstance(data, numpy.ndarray)
7140
        assert data.flags['C_CONTIGUOUS']
7141
        assert data.shape == (64, 64, 3)
7142
        assert data.dtype == numpy.uint8
7143
        assert tuple(data[56, 32, :]) == (239, 243, 247)
7144
        assert_aszarr_method(tif, data)
7145
        assert_decode_method(page)
7146
        assert__str__(tif)
7147

7148

7149
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_CODECS, reason=REASON)
7150
def test_read_generic_series():
7151
    """Test read 4 series in 6 pages."""
7152
    fname = public_file('tifffile/generic_series.tif')
7153
    with TiffFile(fname) as tif:
7154
        assert tif.byteorder == '<'
7155
        assert len(tif.pages) == 6
7156
        assert len(tif.series) == 4
7157
        # assert series 0 properties
7158
        series = tif.series[0]
7159
        assert series.shape == (3, 20, 20)
7160
        assert series.dtype == numpy.uint8
7161
        assert series.axes == 'IYX'
7162
        assert series.kind == 'generic'
7163
        page = series.pages[0]
7164
        assert page.compression == COMPRESSION.LZW
7165
        assert page.imagewidth == 20
7166
        assert page.imagelength == 20
7167
        assert page.bitspersample == 8
7168
        assert page.samplesperpixel == 1
7169
        data = tif.asarray(series=0)
7170
        assert data.flags['C_CONTIGUOUS']
7171
        assert data.shape == (3, 20, 20)
7172
        assert data.dtype == numpy.uint8
7173
        assert tuple(data[:, 9, 9]) == (19, 90, 206)
7174
        assert_aszarr_method(tif, data, series=0)
7175
        # assert series 1 properties
7176
        series = tif.series[1]
7177
        assert series.shape == (10, 10, 3)
7178
        assert series.dtype == numpy.float32
7179
        assert series.axes == 'YXS'
7180
        assert series.kind == 'generic'
7181
        page = series.pages[0]
7182
        assert page.photometric == PHOTOMETRIC.RGB
7183
        assert page.compression == COMPRESSION.LZW
7184
        assert page.imagewidth == 10
7185
        assert page.imagelength == 10
7186
        assert page.bitspersample == 32
7187
        assert page.samplesperpixel == 3
7188
        data = tif.asarray(series=1)
7189
        assert isinstance(data, numpy.ndarray)
7190
        assert data.flags['C_CONTIGUOUS']
7191
        assert data.shape == (10, 10, 3)
7192
        assert data.dtype == numpy.float32
7193
        assert round(abs(data[9, 9, 1] - 214.5733642578125), 7) == 0
7194
        assert_aszarr_method(tif, data, series=1)
7195
        # assert series 2 properties
7196
        series = tif.series[2]
7197
        assert series.shape == (20, 20, 3)
7198
        assert series.dtype == numpy.uint8
7199
        assert series.axes == 'YXS'
7200
        assert series.kind == 'generic'
7201
        page = series.pages[0]
7202
        assert page.photometric == PHOTOMETRIC.RGB
7203
        assert page.compression == COMPRESSION.LZW
7204
        assert page.imagewidth == 20
7205
        assert page.imagelength == 20
7206
        assert page.bitspersample == 8
7207
        assert page.samplesperpixel == 3
7208
        data = tif.asarray(series=2)
7209
        assert isinstance(data, numpy.ndarray)
7210
        assert data.flags['C_CONTIGUOUS']
7211
        assert data.shape == (20, 20, 3)
7212
        assert data.dtype == numpy.uint8
7213
        assert tuple(data[9, 9, :]) == (19, 90, 206)
7214
        assert_aszarr_method(tif, data, series=2)
7215
        # assert series 3 properties
7216
        series = tif.series[3]
7217
        assert series.shape == (10, 10)
7218
        assert series.dtype == numpy.float32
7219
        assert series.axes == 'YX'
7220
        assert series.kind == 'generic'
7221
        page = series.pages[0]
7222
        assert page.compression == COMPRESSION.LZW
7223
        assert page.imagewidth == 10
7224
        assert page.imagelength == 10
7225
        assert page.bitspersample == 32
7226
        assert page.samplesperpixel == 1
7227
        data = tif.asarray(series=3)
7228
        assert isinstance(data, numpy.ndarray)
7229
        assert data.flags['C_CONTIGUOUS']
7230
        assert data.shape == (10, 10)
7231
        assert data.dtype == numpy.float32
7232
        assert round(abs(data[9, 9] - 223.1648712158203), 7) == 0
7233
        assert_aszarr_method(tif, data, series=3)
7234
        assert__str__(tif)
7235

7236

7237
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
7238
def test_read_freeimage():
7239
    """Test read 3 series in 3 pages RGB LZW."""
7240
    fname = private_file('freeimage.tif')
7241
    with TiffFile(fname) as tif:
7242
        assert tif.byteorder == '<'
7243
        assert len(tif.pages) == 3
7244
        assert len(tif.series) == 3
7245
        for i, shape in enumerate(((100, 600), (379, 574), (689, 636))):
7246
            series = tif.series[i]
7247
            shape = shape + (3,)
7248
            assert series.shape == shape
7249
            assert series.dtype == numpy.uint8
7250
            assert series.axes == 'YXS'
7251
            assert series.kind == 'generic'
7252
            page = series.pages[0]
7253
            assert page.photometric == PHOTOMETRIC.RGB
7254
            assert page.compression == COMPRESSION.LZW
7255
            assert page.imagewidth == shape[1]
7256
            assert page.imagelength == shape[0]
7257
            assert page.bitspersample == 8
7258
            assert page.samplesperpixel == 3
7259
            data = tif.asarray(series=i)
7260
            assert isinstance(data, numpy.ndarray)
7261
            assert data.flags['C_CONTIGUOUS']
7262
            assert data.shape == shape
7263
            assert data.dtype == numpy.uint8
7264
            assert_aszarr_method(tif, data, series=i)
7265
            assert__str__(tif)
7266

7267

7268
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
7269
def test_read_leadtools():
7270
    """Test read LeadTools 11-pages with different compression."""
7271
    # https://www.leadtools.com/support/forum/posts/t10960-
7272
    fname = private_file('LeadTools/MultipleFormats.tif')
7273
    with TiffFile(fname) as tif:
7274
        assert tif.byteorder == '<'
7275
        assert len(tif.pages) == 11
7276
        assert len(tif.series) == 11
7277
        assert__str__(tif)
7278
        # 1- Uncompressed bilevel
7279
        page = tif.pages.first
7280
        assert page.photometric == PHOTOMETRIC.MINISBLACK
7281
        assert page.compression == COMPRESSION.NONE
7282
        assert page.imagewidth == 600
7283
        assert page.imagelength == 75
7284
        assert page.bitspersample == 1
7285
        assert page.samplesperpixel == 1
7286
        data = page.asarray()
7287
        assert data.shape == (75, 600)
7288
        assert data.dtype == numpy.bool_
7289
        # 2- Uncompressed CMYK
7290
        page = tif.pages[1]
7291
        assert page.photometric == PHOTOMETRIC.SEPARATED
7292
        assert page.compression == COMPRESSION.NONE
7293
        assert page.imagewidth == 600
7294
        assert page.imagelength == 75
7295
        assert page.bitspersample == 8
7296
        assert page.samplesperpixel == 4
7297
        data = page.asarray()
7298
        assert data.shape == (75, 600, 4)
7299
        assert data.dtype == numpy.uint8
7300
        # 3- JPEG 2000 compression
7301
        page = tif.pages[2]
7302
        assert page.photometric == PHOTOMETRIC.RGB
7303
        assert page.compression == COMPRESSION.JPEG2000
7304
        assert page.imagewidth == 600
7305
        assert page.imagelength == 75
7306
        assert page.bitspersample == 8
7307
        assert page.samplesperpixel == 3
7308
        data = page.asarray()
7309
        assert data.shape == (75, 600, 3)
7310
        assert data.dtype == numpy.uint8
7311
        # 4- JPEG 4:1:1 compression
7312
        page = tif.pages[3]
7313
        assert page.photometric == PHOTOMETRIC.YCBCR
7314
        assert page.compression == COMPRESSION.JPEG
7315
        assert page.imagewidth == 600
7316
        assert page.imagelength == 75
7317
        assert page.bitspersample == 8
7318
        assert page.samplesperpixel == 3
7319
        assert page.tags['YCbCrSubSampling'].value == (2, 2)
7320
        data = page.asarray()
7321
        assert data.shape == (75, 600, 3)
7322
        assert data.dtype == numpy.uint8
7323
        # 5- JBIG compression
7324
        page = tif.pages[4]
7325
        assert page.photometric == PHOTOMETRIC.MINISBLACK
7326
        assert page.compression == COMPRESSION.JBIG
7327
        assert page.imagewidth == 600
7328
        assert page.imagelength == 75
7329
        assert page.bitspersample == 1
7330
        assert page.samplesperpixel == 1
7331
        with pytest.raises(ValueError):
7332
            data = page.asarray()
7333
        # 6- RLE Packbits compression
7334
        page = tif.pages[5]
7335
        assert page.photometric == PHOTOMETRIC.RGB
7336
        assert page.compression == COMPRESSION.PACKBITS
7337
        assert page.imagewidth == 600
7338
        assert page.imagelength == 75
7339
        assert page.bitspersample == 8
7340
        assert page.samplesperpixel == 3
7341
        data = page.asarray()
7342
        assert data.shape == (75, 600, 3)
7343
        assert data.dtype == numpy.uint8
7344
        # 7- CMYK with RLE Packbits compression
7345
        page = tif.pages[6]
7346
        assert page.photometric == PHOTOMETRIC.SEPARATED
7347
        assert page.compression == COMPRESSION.PACKBITS
7348
        assert page.imagewidth == 600
7349
        assert page.imagelength == 75
7350
        assert page.bitspersample == 8
7351
        assert page.samplesperpixel == 4
7352
        data = page.asarray()
7353
        assert data.shape == (75, 600, 4)
7354
        assert data.dtype == numpy.uint8
7355
        # 8- YCC with RLE Packbits compression
7356
        page = tif.pages[7]
7357
        assert page.photometric == PHOTOMETRIC.YCBCR
7358
        assert page.compression == COMPRESSION.PACKBITS
7359
        assert page.imagewidth == 600
7360
        assert page.imagelength == 75
7361
        assert page.bitspersample == 8
7362
        assert page.samplesperpixel == 3
7363
        assert page.tags['YCbCrSubSampling'].value == (2, 1)
7364
        with pytest.raises(NotImplementedError):
7365
            data = page.asarray()
7366
        # 9- LZW compression
7367
        page = tif.pages[8]
7368
        assert page.photometric == PHOTOMETRIC.MINISBLACK
7369
        assert page.compression == COMPRESSION.LZW
7370
        assert page.imagewidth == 600
7371
        assert page.imagelength == 75
7372
        assert page.bitspersample == 1
7373
        assert page.samplesperpixel == 1
7374
        data = page.asarray()
7375
        assert data.shape == (75, 600)
7376
        assert data.dtype == numpy.bool_
7377
        # 10- CCITT Group 4 compression
7378
        page = tif.pages[9]
7379
        assert page.photometric == PHOTOMETRIC.MINISWHITE
7380
        assert page.compression == COMPRESSION.CCITT_T6
7381
        assert page.imagewidth == 600
7382
        assert page.imagelength == 75
7383
        assert page.bitspersample == 1
7384
        assert page.samplesperpixel == 1
7385
        with pytest.raises(ValueError):
7386
            data = page.asarray()
7387
        # 11- CCITT Group 3 2-D compression
7388
        page = tif.pages[10]
7389
        assert page.photometric == PHOTOMETRIC.MINISWHITE
7390
        assert page.compression == COMPRESSION.CCITT_T4
7391
        assert page.imagewidth == 600
7392
        assert page.imagelength == 75
7393
        assert page.bitspersample == 1
7394
        assert page.samplesperpixel == 1
7395
        with pytest.raises(ValueError):
7396
            data = page.asarray()
7397

7398

7399
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
7400
def test_read_12bit():
7401
    """Test read 12 bit images."""
7402
    fname = private_file('12bit.tif')
7403
    with TiffFile(fname) as tif:
7404
        assert tif.byteorder == '<'
7405
        assert len(tif.pages) == 1000
7406
        assert len(tif.series) == 1
7407
        # assert page properties
7408
        page = tif.pages.first
7409
        assert not page.is_contiguous
7410
        assert page.compression == COMPRESSION.NONE
7411
        assert page.imagewidth == 1024
7412
        assert page.imagelength == 304
7413
        assert page.bitspersample == 12
7414
        assert page.samplesperpixel == 1
7415
        # assert series properties
7416
        series = tif.series[0]
7417
        assert series.shape == (1000, 304, 1024)
7418
        assert series.dtype == numpy.uint16
7419
        assert series.axes == 'IYX'
7420
        assert series.kind == 'uniform'
7421
        # assert data
7422
        data = tif.asarray(478)
7423
        assert isinstance(data, numpy.ndarray)
7424
        assert data.flags['C_CONTIGUOUS']
7425
        assert data.shape == (304, 1024)
7426
        assert data.dtype == numpy.uint16
7427
        assert round(abs(data[138, 475] - 40), 7) == 0
7428
        assert_aszarr_method(tif, data, key=478)
7429
        assert__str__(tif, 0)
7430

7431

7432
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_CODECS, reason=REASON)
7433
def test_read_lzw_12bit_table():
7434
    """Test read lzw-full-12-bit-table.tif.
7435

7436
    Also test RowsPerStrip > ImageLength.
7437

7438
    """
7439
    fname = public_file('twelvemonkeys/tiff/lzw-full-12-bit-table.tif')
7440
    with TiffFile(fname) as tif:
7441
        assert len(tif.series) == 1
7442
        assert len(tif.pages) == 1
7443
        page = tif.pages.first
7444
        assert page.photometric == PHOTOMETRIC.MINISBLACK
7445
        assert page.imagewidth == 874
7446
        assert page.imagelength == 1240
7447
        assert page.bitspersample == 8
7448
        assert page.samplesperpixel == 1
7449
        assert page.rowsperstrip == 1240
7450
        assert page.tags['RowsPerStrip'].value == 4294967295
7451
        # assert data
7452
        image = page.asarray()
7453
        assert image.flags['C_CONTIGUOUS']
7454
        assert image[434, 588] == 88
7455
        assert image[400, 600] == 255
7456
        assert_aszarr_method(page, image)
7457
        assert__str__(tif)
7458

7459

7460
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS or SKIP_LARGE, reason=REASON)
7461
def test_read_lzw_large_buffer():
7462
    """Test read LZW compression which requires large buffer."""
7463
    # https://github.com/groupdocs-viewer/GroupDocs.Viewer-for-.NET-MVC-App
7464
    # /issues/35
7465
    fname = private_file('lzw/lzw_large_buffer.tiff')
7466
    with TiffFile(fname) as tif:
7467
        assert len(tif.pages) == 1
7468
        page = tif.pages.first
7469
        assert page.compression == COMPRESSION.LZW
7470
        assert page.imagewidth == 5104
7471
        assert page.imagelength == 8400
7472
        assert page.bitspersample == 8
7473
        assert page.samplesperpixel == 4
7474
        # assert data
7475
        image = page.asarray()
7476
        assert image.shape == (8400, 5104, 4)
7477
        assert image.dtype == numpy.uint8
7478
        image = tif.asarray()
7479
        assert image.shape == (8400, 5104, 4)
7480
        assert image.dtype == numpy.uint8
7481
        assert image[4200, 2550, 0] == 0
7482
        assert image[4200, 2550, 3] == 255
7483
        assert_aszarr_method(tif, image)
7484
        assert__str__(tif)
7485

7486

7487
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
7488
def test_read_lzw_ycbcr_subsampling():
7489
    """Test fail LZW compression with subsampling."""
7490
    fname = private_file('lzw/lzw_ycbcr_subsampling.tif')
7491
    with TiffFile(fname) as tif:
7492
        assert len(tif.pages) == 1
7493
        page = tif.pages.first
7494
        assert page.compression == COMPRESSION.LZW
7495
        assert page.photometric == PHOTOMETRIC.YCBCR
7496
        assert page.planarconfig == PLANARCONFIG.CONTIG
7497
        assert page.imagewidth == 39
7498
        assert page.imagelength == 39
7499
        assert page.bitspersample == 8
7500
        assert page.samplesperpixel == 3
7501
        # assert data
7502
        with pytest.raises(NotImplementedError):
7503
            page.asarray()
7504
        assert__str__(tif)
7505

7506

7507
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
7508
def test_read_ycbcr_subsampling():
7509
    """Test fail YCBCR with subsampling."""
7510
    fname = private_file('ycbcr_subsampling.tif')
7511
    with TiffFile(fname) as tif:
7512
        assert len(tif.pages) == 2
7513
        page = tif.pages.first
7514
        assert page.compression == COMPRESSION.NONE
7515
        assert page.photometric == PHOTOMETRIC.YCBCR
7516
        assert page.planarconfig == PLANARCONFIG.CONTIG
7517
        assert page.imagewidth == 640
7518
        assert page.imagelength == 480
7519
        assert page.bitspersample == 8
7520
        assert page.samplesperpixel == 3
7521
        # assert data
7522
        with pytest.raises(NotImplementedError):
7523
            page.asarray()
7524
        assert__str__(tif)
7525

7526

7527
@pytest.mark.skipif(
7528
    SKIP_PRIVATE or SKIP_CODECS or not imagecodecs.JPEG.available,
7529
    reason=REASON,
7530
)
7531
def test_read_jpeg_baboon():
7532
    """Test JPEG compression."""
7533
    fname = private_file('baboon.tiff')
7534
    with TiffFile(fname) as tif:
7535
        assert tif.byteorder == '<'
7536
        assert len(tif.pages) == 1
7537
        assert len(tif.series) == 1
7538
        # assert page properties
7539
        page = tif.pages.first
7540
        assert 'JPEGTables' in page.tags
7541
        assert not page.is_reduced
7542
        assert not page.is_tiled
7543
        assert page.compression == COMPRESSION.JPEG
7544
        assert page.imagewidth == 512
7545
        assert page.imagelength == 512
7546
        assert page.bitspersample == 8
7547
        # assert series properties
7548
        series = tif.series[0]
7549
        assert series.shape == (512, 512, 3)
7550
        assert series.dtype == numpy.uint8
7551
        assert series.axes == 'YXS'
7552
        assert series.kind == 'uniform'
7553
        # assert data
7554
        # with pytest.raises((ValueError, NotImplementedError)):
7555
        image = tif.asarray()
7556
        assert image.flags['C_CONTIGUOUS']
7557
        assert_aszarr_method(tif, image)
7558
        assert__str__(tif)
7559

7560

7561
@pytest.mark.skipif(
7562
    SKIP_PRIVATE or SKIP_CODECS or not imagecodecs.JPEG.available,
7563
    reason=REASON,
7564
)
7565
def test_read_jpeg_ycbcr():
7566
    """Test read YCBCR JPEG is returned as RGB."""
7567
    fname = private_file('jpeg/jpeg_ycbcr.tiff')
7568
    with TiffFile(fname) as tif:
7569
        assert len(tif.pages) == 1
7570
        page = tif.pages.first
7571
        assert page.compression == COMPRESSION.JPEG
7572
        assert page.photometric == PHOTOMETRIC.YCBCR
7573
        assert page.planarconfig == PLANARCONFIG.CONTIG
7574
        assert page.imagewidth == 128
7575
        assert page.imagelength == 80
7576
        assert page.bitspersample == 8
7577
        assert page.samplesperpixel == 3
7578
        # assert data
7579
        image = tif.asarray()
7580
        assert image.flags['C_CONTIGUOUS']
7581
        assert image.shape == (80, 128, 3)
7582
        assert image.dtype == numpy.uint8
7583
        assert tuple(image[50, 50, :]) == (177, 149, 210)
7584
        # YCBCR (164, 154, 137)
7585
        assert_aszarr_method(tif, image)
7586
        assert_decode_method(page)
7587
        assert__str__(tif)
7588

7589

7590
@pytest.mark.skipif(
7591
    SKIP_PRIVATE or SKIP_CODECS or not imagecodecs.JPEG.available,
7592
    reason=REASON,
7593
)
7594
@pytest.mark.parametrize(
7595
    'fname', ['tiff_tiled_cmyk_jpeg.tif', 'tiff_strip_cmyk_jpeg.tif']
7596
)
7597
def test_read_jpeg_cmyk(fname):
7598
    """Test read JPEG compressed CMYK image."""
7599
    with TiffFile(private_file(f'pillow/{fname}')) as tif:
7600
        assert len(tif.pages) == 1
7601
        page = tif.pages.first
7602
        assert page.compression == COMPRESSION.JPEG
7603
        assert page.photometric == PHOTOMETRIC.SEPARATED
7604
        assert page.shape == (100, 100, 4)
7605
        assert page.dtype == numpy.uint8
7606
        data = page.asarray()
7607
        assert data.shape == (100, 100, 4)
7608
        assert data.dtype == numpy.uint8
7609
        assert tuple(data[46, 49]) == (79, 230, 222, 77)
7610
        assert_aszarr_method(tif, data)
7611
        # assert_decode_method(page)
7612
        assert__str__(tif)
7613

7614

7615
@pytest.mark.skipif(
7616
    SKIP_PRIVATE or SKIP_CODECS or not imagecodecs.JPEG8.available,
7617
    reason=REASON,
7618
)
7619
def test_read_jpeg12_mandril():
7620
    """Test read JPEG 12-bit compression."""
7621
    # JPEG 12-bit
7622
    fname = private_file('jpeg/jpeg12_mandril.tif')
7623
    with TiffFile(fname) as tif:
7624
        assert len(tif.pages) == 1
7625
        page = tif.pages.first
7626
        assert page.compression == COMPRESSION.JPEG
7627
        assert page.photometric == PHOTOMETRIC.YCBCR
7628
        assert page.imagewidth == 512
7629
        assert page.imagelength == 480
7630
        assert page.bitspersample == 12
7631
        assert page.samplesperpixel == 3
7632
        # assert data
7633
        image = tif.asarray()
7634
        assert image.flags['C_CONTIGUOUS']
7635
        assert image.shape == (480, 512, 3)
7636
        assert image.dtype == numpy.uint16
7637
        assert tuple(image[128, 128, :]) == (1685, 1859, 1376)
7638
        # YCBCR (1752, 1836, 2000)
7639
        assert_aszarr_method(tif, image)
7640
        assert__str__(tif)
7641

7642

7643
@pytest.mark.skipif(
7644
    SKIP_PRIVATE
7645
    or SKIP_CODECS
7646
    or SKIP_LARGE
7647
    or not imagecodecs.JPEG.available,
7648
    reason=REASON,
7649
)
7650
def test_read_jpeg_lsb2msb():
7651
    """Test read huge tiled, JPEG compressed, with lsb2msb specified.
7652

7653
    Also test JPEG with RGB photometric.
7654

7655
    """
7656
    fname = private_file('large/jpeg_lsb2msb.tif')
7657
    with TiffFile(fname) as tif:
7658
        assert len(tif.pages) == 1
7659
        page = tif.pages.first
7660
        assert page.compression == COMPRESSION.JPEG
7661
        assert page.photometric == PHOTOMETRIC.RGB
7662
        assert not page.is_jfif
7663
        assert page.imagewidth == 49128
7664
        assert page.imagelength == 59683
7665
        assert page.bitspersample == 8
7666
        assert page.samplesperpixel == 3
7667
        # assert data
7668
        image = tif.asarray()
7669
        assert image.flags['C_CONTIGUOUS']
7670
        assert image.shape == (59683, 49128, 3)
7671
        assert image.dtype == numpy.uint8
7672
        assert tuple(image[38520, 43767, :]) == (255, 255, 255)
7673
        assert tuple(image[47866, 30076, :]) == (52, 39, 23)
7674
        assert__str__(tif)
7675

7676

7677
@pytest.mark.skipif(
7678
    SKIP_PRIVATE
7679
    or SKIP_CODECS
7680
    or not imagecodecs.JPEG.available
7681
    or not imagecodecs.JPEG2K.available,
7682
    reason=REASON,
7683
)
7684
def test_read_aperio_j2k():
7685
    """Test read SVS slide with J2K compression."""
7686
    fname = private_file('slides/CMU-1-JP2K-33005.tif')
7687
    with TiffFile(fname) as tif:
7688
        assert tif.is_svs
7689
        assert len(tif.pages) == 6
7690
        page = tif.pages.first
7691
        assert page.compression == COMPRESSION.APERIO_JP2000_RGB
7692
        assert page.photometric == PHOTOMETRIC.RGB
7693
        assert page.planarconfig == PLANARCONFIG.CONTIG
7694
        assert page.shape == (32893, 46000, 3)
7695
        assert page.dtype == numpy.uint8
7696
        page = tif.pages[1]
7697
        assert page.compression == COMPRESSION.JPEG
7698
        assert page.photometric == PHOTOMETRIC.RGB
7699
        assert page.planarconfig == PLANARCONFIG.CONTIG
7700
        assert page.shape == (732, 1024, 3)
7701
        assert page.dtype == numpy.uint8
7702
        page = tif.pages[2]
7703
        assert page.compression == COMPRESSION.APERIO_JP2000_RGB
7704
        assert page.photometric == PHOTOMETRIC.RGB
7705
        assert page.planarconfig == PLANARCONFIG.CONTIG
7706
        assert page.shape == (8223, 11500, 3)
7707
        assert page.dtype == numpy.uint8
7708
        page = tif.pages[3]
7709
        assert page.compression == COMPRESSION.APERIO_JP2000_RGB
7710
        assert page.photometric == PHOTOMETRIC.RGB
7711
        assert page.planarconfig == PLANARCONFIG.CONTIG
7712
        assert page.shape == (2055, 2875, 3)
7713
        assert page.dtype == numpy.uint8
7714
        page = tif.pages[4]
7715
        assert page.is_reduced
7716
        assert page.compression == COMPRESSION.LZW
7717
        assert page.photometric == PHOTOMETRIC.RGB
7718
        assert page.planarconfig == PLANARCONFIG.CONTIG
7719
        assert page.shape == (463, 387, 3)
7720
        assert page.dtype == numpy.uint8
7721
        page = tif.pages[5]
7722
        assert page.is_reduced
7723
        assert page.compression == COMPRESSION.JPEG
7724
        assert page.photometric == PHOTOMETRIC.RGB
7725
        assert page.planarconfig == PLANARCONFIG.CONTIG
7726
        assert page.shape == (431, 1280, 3)
7727
        assert page.dtype == numpy.uint8
7728
        # assert data
7729
        image = tif.pages[3].asarray()
7730
        assert image.flags['C_CONTIGUOUS']
7731
        assert image.shape == (2055, 2875, 3)
7732
        assert image.dtype == numpy.uint8
7733
        assert image[512, 1024, 0] == 246
7734
        assert image[512, 1024, 1] == 245
7735
        assert image[512, 1024, 2] == 245
7736

7737
        assert_decode_method(tif.pages[3], image)
7738
        assert__str__(tif)
7739

7740

7741
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
7742
def test_read_lzma():
7743
    """Test read LZMA compression."""
7744
    # 512x512, uint8, lzma compression
7745
    fname = private_file('lzma.tif')
7746
    with TiffFile(fname) as tif:
7747
        assert tif.byteorder == '<'
7748
        assert len(tif.pages) == 1
7749
        assert len(tif.series) == 1
7750
        # assert page properties
7751
        page = tif.pages.first
7752
        assert page.compression == COMPRESSION.LZMA
7753
        assert page.photometric == PHOTOMETRIC.MINISBLACK
7754
        assert page.imagewidth == 512
7755
        assert page.imagelength == 512
7756
        assert page.bitspersample == 8
7757
        assert page.samplesperpixel == 1
7758
        # assert series properties
7759
        series = tif.series[0]
7760
        assert series.shape == (512, 512)
7761
        assert series.dtype == numpy.uint8
7762
        assert series.axes == 'YX'
7763
        assert series.kind == 'shaped'
7764
        # assert data
7765
        data = tif.asarray()
7766
        assert data.flags['C_CONTIGUOUS']
7767
        assert isinstance(data, numpy.ndarray)
7768
        assert data.shape == (512, 512)
7769
        assert data.dtype == numpy.uint8
7770
        assert data[273, 426] == 151
7771
        assert_aszarr_method(tif, data)
7772
        assert__str__(tif)
7773

7774

7775
@pytest.mark.skipif(
7776
    SKIP_PUBLIC or SKIP_CODECS or not imagecodecs.WEBP.available, reason=REASON
7777
)
7778
def test_read_webp():
7779
    """Test read WebP compression."""
7780
    fname = public_file('GDAL/tif_webp.tif')
7781
    with TiffFile(fname) as tif:
7782
        assert len(tif.pages) == 1
7783
        page = tif.pages.first
7784
        assert page.compression == COMPRESSION.WEBP
7785
        assert page.photometric == PHOTOMETRIC.RGB
7786
        assert page.planarconfig == PLANARCONFIG.CONTIG
7787
        assert page.imagewidth == 50
7788
        assert page.imagelength == 50
7789
        assert page.bitspersample == 8
7790
        assert page.samplesperpixel == 3
7791
        # assert data
7792
        image = tif.asarray()
7793
        assert image.flags['C_CONTIGUOUS']
7794
        assert image.shape == (50, 50, 3)
7795
        assert image.dtype == numpy.uint8
7796
        assert image[25, 25, 0] == 92
7797
        assert image[25, 25, 1] == 122
7798
        assert image[25, 25, 2] == 37
7799
        assert_aszarr_method(tif, image)
7800
        assert__str__(tif)
7801

7802

7803
@pytest.mark.skipif(
7804
    SKIP_PUBLIC or SKIP_CODECS or not imagecodecs.LERC.available, reason=REASON
7805
)
7806
def test_read_lerc():
7807
    """Test read LERC compression."""
7808
    if not hasattr(imagecodecs, 'LERC'):
7809
        pytest.skip('LERC codec missing')
7810

7811
    fname = public_file('imagecodecs/rgb.u2.lerc.tif')
7812
    with TiffFile(fname) as tif:
7813
        assert len(tif.pages) == 1
7814
        page = tif.pages.first
7815
        assert page.compression == COMPRESSION.LERC
7816
        assert page.photometric == PHOTOMETRIC.RGB
7817
        assert page.planarconfig == PLANARCONFIG.CONTIG
7818
        assert page.imagewidth == 31
7819
        assert page.imagelength == 32
7820
        assert page.bitspersample == 16
7821
        assert page.samplesperpixel == 3
7822
        # assert data
7823
        image = tif.asarray()
7824
        assert image.flags['C_CONTIGUOUS']
7825
        assert image.shape == (32, 31, 3)
7826
        assert image.dtype == numpy.uint16
7827
        assert tuple(image[25, 25]) == (3265, 1558, 2811)
7828
        assert_aszarr_method(tif, image)
7829
        assert__str__(tif)
7830

7831

7832
@pytest.mark.skipif(
7833
    SKIP_PUBLIC or SKIP_CODECS or not imagecodecs.ZSTD.available, reason=REASON
7834
)
7835
def test_read_zstd():
7836
    """Test read ZStd compression."""
7837
    fname = public_file('GDAL/byte_zstd.tif')
7838
    with TiffFile(fname) as tif:
7839
        assert len(tif.pages) == 1
7840
        page = tif.pages.first
7841
        assert page.compression == COMPRESSION.ZSTD
7842
        assert page.photometric == PHOTOMETRIC.MINISBLACK
7843
        assert page.planarconfig == PLANARCONFIG.CONTIG
7844
        assert page.imagewidth == 20
7845
        assert page.imagelength == 20
7846
        assert page.bitspersample == 8
7847
        assert page.samplesperpixel == 1
7848
        # assert data
7849
        image = tif.asarray()  # fails with imagecodecs <= 2018.11.8
7850
        assert image.flags['C_CONTIGUOUS']
7851
        assert image.shape == (20, 20)
7852
        assert image.dtype == numpy.uint8
7853
        assert image[18, 1] == 247
7854
        assert_aszarr_method(tif, image)
7855
        assert__str__(tif)
7856

7857

7858
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_CODECS, reason=REASON)
7859
def test_read_jetraw():
7860
    """Test read Jetraw compression."""
7861
    try:
7862
        have_jetraw = imagecodecs.JETRAW.available
7863
    except AttributeError:
7864
        # requires imagecodecs > 2022.22.2
7865
        have_jetraw = False
7866

7867
    fname = private_file('jetraw/16ms-1.p.tif')
7868
    with TiffFile(fname) as tif:
7869
        assert len(tif.pages) == 1
7870
        page = tif.pages.first
7871
        assert page.compression == COMPRESSION.JETRAW
7872
        assert page.photometric == PHOTOMETRIC.MINISBLACK
7873
        assert page.planarconfig == PLANARCONFIG.CONTIG
7874
        assert page.imagewidth == 2304
7875
        assert page.imagelength == 2304
7876
        assert page.bitspersample == 16
7877
        assert page.samplesperpixel == 1
7878
        assert__str__(tif)
7879
        # assert data
7880
        if not have_jetraw:
7881
            pytest.skip('Jetraw codec not available')
7882
        image = tif.asarray()
7883
        assert image[1490, 1830] == 36554
7884
        assert_aszarr_method(tif, image)
7885

7886

7887
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_CODECS, reason=REASON)
7888
def test_read_pixtiff():
7889
    """Test read PIXTIFF compression."""
7890
    # https://github.com/haraldk/TwelveMonkeys/issues/307
7891

7892
    fname = private_file('PIXTIFF/pixtiff_1bpp.tif')
7893
    with TiffFile(fname) as tif:
7894
        page = tif.pages.first
7895
        assert page.compression == COMPRESSION.PIXTIFF
7896
        assert page.photometric == PHOTOMETRIC.MINISBLACK
7897
        assert page.imagewidth == 801
7898
        assert page.imagelength == 1313
7899
        assert page.bitspersample == 1
7900
        assert page.samplesperpixel == 1
7901
        assert__str__(tif)
7902
        image = tif.asarray()
7903
        assert image.dtype == numpy.bool_
7904
        assert image.shape == (1313, 801)
7905
        assert not image[1000, 700]
7906

7907
    fname = private_file('PIXTIFF/pixtiff_4bpp.tif')
7908
    with TiffFile(fname) as tif:
7909
        page = tif.pages.first
7910
        assert page.compression == COMPRESSION.PIXTIFF
7911
        assert page.photometric == PHOTOMETRIC.MINISBLACK
7912
        assert page.imagewidth == 801
7913
        assert page.imagelength == 1313
7914
        assert page.bitspersample == 4
7915
        assert page.samplesperpixel == 1
7916
        assert__str__(tif)
7917
        image = tif.asarray()
7918
        assert image.dtype == numpy.uint8
7919
        assert image.shape == (1313, 801)
7920
        assert image[1000, 700] == 6
7921

7922
    fname = private_file('PIXTIFF/pixtiff_8bpp_rgb.tif')
7923
    with TiffFile(fname) as tif:
7924
        page = tif.pages.first
7925
        assert page.compression == COMPRESSION.PIXTIFF
7926
        assert page.photometric == PHOTOMETRIC.RGB
7927
        assert page.imagewidth == 801
7928
        assert page.imagelength == 1313
7929
        assert page.bitspersample == 8
7930
        assert page.samplesperpixel == 3
7931
        assert__str__(tif)
7932
        image = tif.asarray()
7933
        assert image.dtype == numpy.uint8
7934
        assert image.shape == (1313, 801, 3)
7935
        assert tuple(image[1000, 700]) == (89, 70, 80)
7936

7937

7938
@pytest.mark.skipif(
7939
    SKIP_PRIVATE or SKIP_CODECS or not imagecodecs.LJPEG.available,
7940
    reason=REASON,
7941
)
7942
def test_read_dng():
7943
    """Test read JPEG compressed CFA image in SubIFD."""
7944
    fname = private_file('DNG/IMG_0793.DNG')
7945
    with TiffFile(fname) as tif:
7946
        assert len(tif.pages) == 1
7947
        assert len(tif.series) == 2
7948
        page = tif.pages.first
7949
        assert page.index == 0
7950
        assert page.shape == (640, 852, 3)
7951
        assert page.bitspersample == 8
7952
        data = page.asarray()
7953
        assert_aszarr_method(tif, data)
7954
        page = tif.pages.first.pages[0]
7955
        assert page.is_tiled
7956
        assert page.treeindex == (0, 0)
7957
        assert page.compression == COMPRESSION.JPEG
7958
        assert page.photometric == PHOTOMETRIC.CFA
7959
        assert page.shape == (3024, 4032)
7960
        assert page.bitspersample == 16
7961
        assert page.tags['CFARepeatPatternDim'].value == (2, 2)
7962
        assert page.tags['CFAPattern'].value == b'\x00\x01\x01\x02'
7963
        data = page.asarray()
7964
        assert_aszarr_method(tif.series[1], data)
7965
        assert__str__(tif)
7966

7967

7968
@pytest.mark.skipif(
7969
    SKIP_PRIVATE or SKIP_CODECS or not imagecodecs.LJPEG.available,
7970
    reason=REASON,
7971
)
7972
def test_read_cfa():
7973
    """Test read 14-bit uncompressed and JPEG compressed CFA image."""
7974
    fname = private_file('DNG/cinemadng/M14-1451_000085_cDNG_uncompressed.dng')
7975
    with TiffFile(fname) as tif:
7976
        assert len(tif.pages) == 1
7977
        page = tif.pages.first
7978
        assert page.compression == 1
7979
        assert page.photometric == PHOTOMETRIC.CFA
7980
        assert page.imagewidth == 960
7981
        assert page.imagelength == 540
7982
        assert page.bitspersample == 14
7983
        assert page.tags['CFARepeatPatternDim'].value == (2, 2)
7984
        assert page.tags['CFAPattern'].value == b'\x00\x01\x01\x02'
7985
        data = page.asarray()
7986
        assert_aszarr_method(tif, data)
7987

7988
    fname = private_file('DNG/cinemadng/M14-1451_000085_cDNG_compressed.dng')
7989
    with TiffFile(fname) as tif:
7990
        assert len(tif.pages) == 1
7991
        page = tif.pages.first
7992
        assert page.compression == COMPRESSION.JPEG
7993
        assert page.photometric == PHOTOMETRIC.CFA
7994
        assert page.imagewidth == 960
7995
        assert page.imagelength == 540
7996
        assert page.bitspersample == 14
7997
        assert page.tags['CFARepeatPatternDim'].value == (2, 2)
7998
        assert page.tags['CFAPattern'].value == b'\x00\x01\x01\x02'
7999
        image = page.asarray()
8000
        assert_array_equal(image, data)
8001
        assert_aszarr_method(tif, data)
8002

8003

8004
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
8005
def test_read_lena_be_f16_contig():
8006
    """Test read big endian float16 horizontal differencing."""
8007
    fname = private_file('PS/lena_be_f16_contig.tif')
8008
    with TiffFile(fname) as tif:
8009
        assert tif.byteorder == '>'
8010
        assert len(tif.pages) == 1
8011
        assert len(tif.series) == 1
8012
        # assert page properties
8013
        page = tif.pages.first
8014
        assert not page.is_reduced
8015
        assert not page.is_tiled
8016
        assert page.compression == COMPRESSION.NONE
8017
        assert page.imagewidth == 512
8018
        assert page.imagelength == 512
8019
        assert page.bitspersample == 16
8020
        assert page.samplesperpixel == 3
8021
        # assert series properties
8022
        series = tif.series[0]
8023
        assert series.shape == (512, 512, 3)
8024
        assert series.dtype == numpy.float16
8025
        assert series.axes == 'YXS'
8026
        assert series.kind == 'imagej'
8027
        # assert data
8028
        data = tif.asarray(series=0)
8029
        assert isinstance(data, numpy.ndarray)
8030
        assert data.flags['C_CONTIGUOUS']
8031
        assert data.shape == (512, 512, 3)
8032
        assert data.dtype == numpy.float16
8033
        assert_array_almost_equal(data[256, 256], (0.4563, 0.052856, 0.064819))
8034
        assert_aszarr_method(tif, data, series=0)
8035
        assert_decode_method(page)
8036
        assert__str__(tif)
8037

8038

8039
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
8040
def test_read_lena_be_f16_lzw_planar():
8041
    """Test read big endian, float16, LZW, horizontal differencing."""
8042
    fname = private_file('PS/lena_be_f16_lzw_planar.tif')
8043
    with TiffFile(fname, is_imagej=False) as tif:
8044
        assert tif.byteorder == '>'
8045
        assert len(tif.pages) == 1
8046
        assert len(tif.series) == 1
8047
        assert not tif.is_imagej
8048
        # assert page properties
8049
        page = tif.pages.first
8050
        assert not page.is_reduced
8051
        assert not page.is_tiled
8052
        assert page.compression == COMPRESSION.LZW
8053
        assert page.imagewidth == 512
8054
        assert page.imagelength == 512
8055
        assert page.bitspersample == 16
8056
        assert page.samplesperpixel == 3
8057
        # assert series properties
8058
        series = tif.series[0]
8059
        assert series.shape == (3, 512, 512)
8060
        assert series.dtype == numpy.float16
8061
        assert series.axes == 'SYX'
8062
        assert series.kind == 'uniform'
8063
        # assert data
8064
        data = tif.asarray(series=0)
8065
        assert isinstance(data, numpy.ndarray)
8066
        assert data.flags['C_CONTIGUOUS']
8067
        assert data.shape == (3, 512, 512)
8068
        assert data.dtype == numpy.float16
8069
        assert_array_almost_equal(
8070
            data[:, 256, 256], (0.4563, 0.052856, 0.064819)
8071
        )
8072
        assert_aszarr_method(tif, data, series=0)
8073
        assert_decode_method(page)
8074
        assert__str__(tif)
8075

8076

8077
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
8078
def test_read_lena_be_f32_deflate_contig():
8079
    """Test read big endian, float32 horizontal differencing, deflate."""
8080
    fname = private_file('PS/lena_be_f32_deflate_contig.tif')
8081
    with TiffFile(fname, is_imagej=False) as tif:
8082
        assert tif.byteorder == '>'
8083
        assert len(tif.pages) == 1
8084
        assert len(tif.series) == 1
8085
        assert not tif.is_imagej
8086
        # assert page properties
8087
        page = tif.pages.first
8088
        assert not page.is_reduced
8089
        assert not page.is_tiled
8090
        assert page.compression == COMPRESSION.ADOBE_DEFLATE
8091
        assert page.imagewidth == 512
8092
        assert page.imagelength == 512
8093
        assert page.bitspersample == 32
8094
        assert page.samplesperpixel == 3
8095
        # assert series properties
8096
        series = tif.series[0]
8097
        assert series.shape == (512, 512, 3)
8098
        assert series.dtype == numpy.float32
8099
        assert series.axes == 'YXS'
8100
        assert series.kind == 'uniform'
8101
        # assert data
8102
        data = tif.asarray(series=0)
8103
        assert isinstance(data, numpy.ndarray)
8104
        assert data.flags['C_CONTIGUOUS']
8105
        assert data.shape == (512, 512, 3)
8106
        assert data.dtype == numpy.float32
8107
        assert_array_almost_equal(
8108
            data[256, 256], (0.456386, 0.052867, 0.064795)
8109
        )
8110
        assert_aszarr_method(tif, data, series=0)
8111
        assert__str__(tif)
8112

8113

8114
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
8115
def test_read_lena_le_f32_lzw_planar():
8116
    """Test read little endian, LZW, float32 horizontal differencing."""
8117
    fname = private_file('PS/lena_le_f32_lzw_planar.tif')
8118
    with TiffFile(fname, is_imagej=False) as tif:
8119
        assert tif.byteorder == '<'
8120
        assert len(tif.pages) == 1
8121
        assert len(tif.series) == 1
8122
        assert not tif.is_imagej
8123
        # assert page properties
8124
        page = tif.pages.first
8125
        assert not page.is_reduced
8126
        assert not page.is_tiled
8127
        assert page.compression == COMPRESSION.LZW
8128
        assert page.imagewidth == 512
8129
        assert page.imagelength == 512
8130
        assert page.bitspersample == 32
8131
        assert page.samplesperpixel == 3
8132
        # assert series properties
8133
        series = tif.series[0]
8134
        assert series.shape == (3, 512, 512)
8135
        assert series.dtype == numpy.float32
8136
        assert series.axes == 'SYX'
8137
        assert series.kind == 'uniform'
8138
        # assert data
8139
        data = tif.asarray(series=0)
8140
        assert isinstance(data, numpy.ndarray)
8141
        assert data.flags['C_CONTIGUOUS']
8142
        assert data.shape == (3, 512, 512)
8143
        assert data.dtype == numpy.float32
8144
        assert_array_almost_equal(
8145
            data[:, 256, 256], (0.456386, 0.052867, 0.064795)
8146
        )
8147
        assert_aszarr_method(tif, data, series=0)
8148
        assert__str__(tif)
8149

8150

8151
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
8152
def test_read_lena_be_rgb48():
8153
    """Test read RGB48."""
8154
    fname = private_file('PS/lena_be_rgb48.tif')
8155
    with TiffFile(fname) as tif:
8156
        assert tif.byteorder == '>'
8157
        assert len(tif.pages) == 1
8158
        assert len(tif.series) == 1
8159
        # assert page properties
8160
        page = tif.pages.first
8161
        assert not page.is_reduced
8162
        assert not page.is_tiled
8163
        assert page.compression == COMPRESSION.NONE
8164
        assert page.imagewidth == 512
8165
        assert page.imagelength == 512
8166
        assert page.bitspersample == 16
8167
        assert page.samplesperpixel == 3
8168
        # assert series properties
8169
        series = tif.series[0]
8170
        assert series.shape == (512, 512, 3)
8171
        assert series.dtype == numpy.uint16
8172
        assert series.axes == 'YXS'
8173
        assert series.kind == 'imagej'
8174
        # assert data
8175
        data = tif.asarray(series=0)
8176
        assert isinstance(data, numpy.ndarray)
8177
        assert data.flags['C_CONTIGUOUS']
8178
        assert data.shape == (512, 512, 3)
8179
        assert data.dtype == numpy.uint16
8180
        assert_array_equal(data[256, 256], (46259, 16706, 18504))
8181
        assert_aszarr_method(tif, data, series=0)
8182
        assert__str__(tif)
8183

8184

8185
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_LARGE or IS_PYPY, reason=REASON)
8186
def test_read_huge_ps5_memmap():
8187
    """Test read 30000x30000 float32 contiguous."""
8188
    # TODO: segfault on pypy3.7-v7.3.5rc2-win64
8189
    fname = private_file('large/huge_ps5.tif')
8190
    with TiffFile(fname) as tif:
8191
        assert tif.byteorder == '<'
8192
        assert len(tif.pages) == 1
8193
        assert len(tif.series) == 1
8194
        # assert page properties
8195
        page = tif.pages.first
8196
        assert page.dataoffsets[0] == 21890
8197
        assert page.nbytes == 3600000000
8198
        assert not page.is_memmappable  # data not aligned!
8199
        assert page.compression == COMPRESSION.NONE
8200
        assert page.imagewidth == 30000
8201
        assert page.imagelength == 30000
8202
        assert page.bitspersample == 32
8203
        assert page.samplesperpixel == 1
8204
        # assert series properties
8205
        series = tif.series[0]
8206
        assert series.shape == (30000, 30000)
8207
        assert series.dtype == numpy.float32
8208
        assert series.axes == 'YX'
8209
        assert series.kind == 'uniform'
8210
        # assert data
8211
        data = tif.asarray(out='memmap')  # memmap in a temp file
8212
        assert isinstance(data, numpy.memmap)
8213
        assert data.flags['C_CONTIGUOUS']
8214
        assert data.shape == (30000, 30000)
8215
        assert data.dtype == numpy.float32
8216
        assert data[6597, 8135] == 0.008780896663665771
8217
        assert_aszarr_method(tif, data)
8218
        del data
8219
        assert not tif.filehandle.closed
8220
        assert__str__(tif)
8221

8222

8223
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_LARGE, reason=REASON)
8224
def test_read_movie():
8225
    """Test read 30000 pages, uint16."""
8226
    fname = public_file('tifffile/movie.tif')
8227
    with TiffFile(fname) as tif:
8228
        assert tif.byteorder == '<'
8229
        assert len(tif.pages) == 30000
8230
        assert len(tif.series) == 1
8231
        assert tif.is_uniform
8232
        # assert series properties
8233
        series = tif.series[0]
8234
        assert series.shape == (30000, 64, 64)
8235
        assert series.dtype == numpy.uint16
8236
        assert series.axes == 'IYX'
8237
        assert series.kind == 'uniform'
8238
        # assert page properties
8239
        page = tif.pages[-1]
8240
        if tif.pages.cache:
8241
            assert isinstance(page, TiffFrame)
8242
        else:
8243
            assert isinstance(page, TiffPage)
8244
        assert page.shape == (64, 64)
8245
        page = tif.pages[-3]
8246
        if tif.pages.cache:
8247
            assert isinstance(page, TiffFrame)
8248
        else:
8249
            assert isinstance(page, TiffPage)
8250
        # assert data
8251
        data = tif.pages[29999].asarray()  # last frame
8252
        assert isinstance(data, numpy.ndarray)
8253
        assert data.flags['C_CONTIGUOUS']
8254
        assert data.shape == (64, 64)
8255
        assert data.dtype == numpy.uint16
8256
        assert data[32, 32] == 460
8257
        del data
8258
        # read selected pages
8259
        # https://github.com/blink1073/tifffile/issues/51
8260
        data = tif.asarray(key=[31, 999, 29999])
8261
        assert data.flags['C_CONTIGUOUS']
8262
        assert data.shape == (3, 64, 64)
8263
        assert data[2, 32, 32] == 460
8264
        del data
8265
        assert__str__(tif, 0)
8266

8267

8268
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_LARGE, reason=REASON)
8269
def test_read_movie_memmap():
8270
    """Test read 30000 pages memory-mapped."""
8271
    fname = public_file('tifffile/movie.tif')
8272
    with TiffFile(fname) as tif:
8273
        # assert data
8274
        data = tif.asarray(out='memmap')
8275
        assert isinstance(data, numpy.memmap)
8276
        assert data.flags['C_CONTIGUOUS']
8277
        assert data.shape == (30000, 64, 64)
8278
        assert data.dtype == numpy.dtype('<u2')
8279
        assert data[29999, 32, 32] == 460
8280
        del data
8281
        assert not tif.filehandle.closed
8282
        assert__str__(tif, 0)
8283

8284

8285
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_LARGE, reason=REASON)
8286
def test_read_100000_pages_movie():
8287
    """Test read 100000x64x64 big endian in memory."""
8288
    fname = public_file('tifffile/100000_pages.tif')
8289
    with TiffFile(fname, _useframes=True) as tif:
8290
        assert tif.is_imagej
8291
        assert tif.byteorder == '>'
8292
        assert len(tif.pages) == 100000
8293
        assert len(tif.series) == 1
8294
        # assert series properties
8295
        series = tif.series[0]
8296
        assert series.shape == (100000, 64, 64)
8297
        assert series.dtype == numpy.uint16
8298
        assert series.axes == 'TYX'
8299
        assert series.kind == 'imagej'
8300
        # assert page properties
8301
        frame = tif.pages[100]
8302
        assert isinstance(frame, TiffFrame)  # uniform=True
8303
        assert frame.shape == (64, 64)
8304
        frame = tif.pages.first
8305
        assert frame.imagewidth == 64
8306
        assert frame.imagelength == 64
8307
        assert frame.bitspersample == 16
8308
        assert frame.compression == 1
8309
        assert frame.shape == (64, 64)
8310
        assert frame.shaped == (1, 1, 64, 64, 1)
8311
        assert frame.ndim == 2
8312
        assert frame.size == 4096
8313
        assert frame.nbytes == 8192
8314
        assert frame.axes == 'YX'
8315
        assert frame._nextifd() == 819200206
8316
        assert frame.is_final
8317
        assert frame.is_contiguous
8318
        assert frame.is_memmappable
8319
        assert frame.hash
8320
        assert frame.decode
8321
        assert frame.aszarr()
8322
        # assert ImageJ tags
8323
        ijmeta = tif.imagej_metadata
8324
        assert ijmeta is not None
8325
        assert ijmeta['ImageJ'] == '1.48g'
8326
        assert round(abs(ijmeta['max'] - 119.0), 7) == 0
8327
        assert round(abs(ijmeta['min'] - 86.0), 7) == 0
8328
        # assert data
8329
        data = tif.asarray()
8330
        assert data.flags['C_CONTIGUOUS']
8331
        assert data.shape == (100000, 64, 64)
8332
        assert data.dtype == numpy.uint16
8333
        assert round(abs(data[7310, 25, 25] - 100), 7) == 0
8334
        # too slow: assert_aszarr_method(tif, data)
8335
        del data
8336
        assert__str__(tif, 0)
8337

8338

8339
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_LARGE, reason=REASON)
8340
def test_read_chart_bl():
8341
    """Test read 13228x18710, 1 bit, no bitspersample tag."""
8342
    fname = public_file('tifffile/chart_bl.tif')
8343
    with TiffFile(fname) as tif:
8344
        assert tif.byteorder == '<'
8345
        assert len(tif.pages) == 1
8346
        assert len(tif.series) == 1
8347
        # assert page properties
8348
        page = tif.pages.first
8349
        assert page.compression == COMPRESSION.NONE
8350
        assert page.imagewidth == 13228
8351
        assert page.imagelength == 18710
8352
        assert page.bitspersample == 1
8353
        assert page.samplesperpixel == 1
8354
        assert page.rowsperstrip == 18710
8355
        # assert series properties
8356
        series = tif.series[0]
8357
        assert series.shape == (18710, 13228)
8358
        assert series.dtype == numpy.bool_
8359
        assert series.axes == 'YX'
8360
        assert series.kind == 'uniform'
8361
        # assert data
8362
        data = tif.asarray()
8363
        assert isinstance(data, numpy.ndarray)
8364
        assert data.flags['C_CONTIGUOUS']
8365
        assert data.shape == (18710, 13228)
8366
        assert data.dtype == numpy.bool_
8367
        assert data[0, 0] is numpy.bool_(True)
8368
        assert data[5000, 5000] is numpy.bool_(False)
8369
        if not SKIP_LARGE:
8370
            assert_aszarr_method(tif, data)
8371
        assert__str__(tif)
8372

8373

8374
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_LARGE, reason=REASON)
8375
def test_read_srtm_20_13():
8376
    """Test read 6000x6000 int16 GDAL."""
8377
    fname = private_file('large/srtm_20_13.tif')
8378
    with TiffFile(fname) as tif:
8379
        assert tif.byteorder == '<'
8380
        assert len(tif.pages) == 1
8381
        assert len(tif.series) == 1
8382
        # assert page properties
8383
        page = tif.pages.first
8384
        assert page.is_contiguous
8385
        assert page.compression == COMPRESSION.NONE
8386
        assert page.imagewidth == 6000
8387
        assert page.imagelength == 6000
8388
        assert page.bitspersample == 16
8389
        assert page.samplesperpixel == 1
8390
        assert page.nodata == -32768
8391
        assert page.tags['GDAL_NODATA'].value == '-32768'
8392
        assert page.tags['GeoAsciiParamsTag'].value == 'WGS 84|'
8393
        # assert series properties
8394
        series = tif.series[0]
8395
        assert series.shape == (6000, 6000)
8396
        assert series.dtype == numpy.int16
8397
        assert series.axes == 'YX'
8398
        assert series.kind == 'uniform'
8399
        # assert data
8400
        data = tif.asarray()
8401
        assert isinstance(data, numpy.ndarray)
8402
        assert data.flags['C_CONTIGUOUS']
8403
        assert data.shape == (6000, 6000)
8404
        assert data.dtype == numpy.int16
8405
        assert data[5199, 5107] == 1019
8406
        assert data[0, 0] == -32768
8407
        assert_aszarr_method(tif, data)
8408
        del data
8409
        assert__str__(tif)
8410

8411

8412
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS or SKIP_LARGE, reason=REASON)
8413
def test_read_gel_scan():
8414
    """Test read 6976x4992x3 uint8 LZW."""
8415
    fname = private_file('large/gel_1-scan2.tif')
8416
    with TiffFile(fname) as tif:
8417
        assert tif.byteorder == '<'
8418
        assert len(tif.pages) == 1
8419
        assert len(tif.series) == 1
8420
        # assert page properties
8421
        page = tif.pages.first
8422
        assert page.photometric == PHOTOMETRIC.RGB
8423
        assert page.compression == COMPRESSION.LZW
8424
        assert page.imagewidth == 4992
8425
        assert page.imagelength == 6976
8426
        assert page.bitspersample == 8
8427
        assert page.samplesperpixel == 3
8428
        # assert series properties
8429
        series = tif.series[0]
8430
        assert series.shape == (6976, 4992, 3)
8431
        assert series.dtype == numpy.uint8
8432
        assert series.axes == 'YXS'
8433
        assert series.kind == 'uniform'
8434
        # assert data
8435
        data = tif.asarray()
8436
        assert isinstance(data, numpy.ndarray)
8437
        assert data.flags['C_CONTIGUOUS']
8438
        assert data.shape == (6976, 4992, 3)
8439
        assert data.dtype == numpy.uint8
8440
        assert tuple(data[2229, 1080, :]) == (164, 164, 164)
8441
        assert_aszarr_method(tif, data)
8442
        del data
8443
        assert__str__(tif)
8444

8445

8446
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
8447
def test_read_caspian():
8448
    """Test read 3x220x279 float64, RGB, deflate, GDAL."""
8449
    fname = public_file('juicypixels/caspian.tif')
8450
    with TiffFile(fname) as tif:
8451
        assert tif.byteorder == '<'
8452
        assert len(tif.pages) == 1
8453
        assert len(tif.series) == 1
8454
        # assert page properties
8455
        page = tif.pages.first
8456
        assert page.photometric == PHOTOMETRIC.RGB
8457
        assert page.planarconfig == PLANARCONFIG.SEPARATE
8458
        assert page.compression == COMPRESSION.DEFLATE
8459
        assert page.imagewidth == 279
8460
        assert page.imagelength == 220
8461
        assert page.bitspersample == 64
8462
        assert page.samplesperpixel == 3
8463
        assert page.tags['GDAL_METADATA'].value.startswith('<GDALMetadata>')
8464
        # assert series properties
8465
        series = tif.series[0]
8466
        assert series.shape == (3, 220, 279)
8467
        assert series.dtype == numpy.float64
8468
        assert series.axes == 'SYX'
8469
        assert series.kind == 'uniform'
8470
        # assert data
8471
        data = tif.asarray()
8472
        assert isinstance(data, numpy.ndarray)
8473
        assert data.flags['C_CONTIGUOUS']
8474
        assert data.shape == (3, 220, 279)
8475
        assert data.dtype == numpy.float64
8476
        assert round(abs(data[2, 100, 140] - 353.0), 7) == 0
8477
        assert_aszarr_method(tif, data)
8478
        assert__str__(tif)
8479

8480

8481
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
8482
def test_read_subifds_array():
8483
    """Test read SubIFDs."""
8484
    fname = public_file('Tiff-Library-4J/IFD struct/SubIFDs array E.tif')
8485
    with TiffFile(fname) as tif:
8486
        assert len(tif.pages) == 1
8487

8488
        # make sure no pyramid was detected
8489
        assert len(tif.series) == 5
8490
        assert tif.series[0].shape == (1500, 2000, 3)
8491
        assert tif.series[1].shape == (1200, 1600, 3)
8492
        assert tif.series[2].shape == (900, 1200, 3)
8493
        assert tif.series[3].shape == (600, 800, 3)
8494
        assert tif.series[4].shape == (300, 400, 3)
8495

8496
        page = tif.pages.first
8497
        assert page.photometric == PHOTOMETRIC.RGB
8498
        assert page.imagewidth == 2000
8499
        assert page.imagelength == 1500
8500
        assert page.bitspersample == 8
8501
        assert page.samplesperpixel == 3
8502
        assert page.tags['SubIFDs'].value == (
8503
            14760220,
8504
            18614796,
8505
            19800716,
8506
            18974964,
8507
        )
8508
        # assert subifds
8509
        assert len(page.pages) == 4
8510
        page = tif.pages.first.pages[0]
8511
        assert page.photometric == PHOTOMETRIC.RGB
8512
        assert page.imagewidth == 1600
8513
        assert page.imagelength == 1200
8514
        assert_aszarr_method(page)
8515
        page = tif.pages.first.pages[1]
8516
        assert page.photometric == PHOTOMETRIC.RGB
8517
        assert page.imagewidth == 1200
8518
        assert page.imagelength == 900
8519
        assert_aszarr_method(page)
8520
        page = tif.pages.first.pages[2]
8521
        assert page.photometric == PHOTOMETRIC.RGB
8522
        assert page.imagewidth == 800
8523
        assert page.imagelength == 600
8524
        assert_aszarr_method(page)
8525
        page = tif.pages.first.pages[3]
8526
        assert page.photometric == PHOTOMETRIC.RGB
8527
        assert page.imagewidth == 400
8528
        assert page.imagelength == 300
8529
        assert_aszarr_method(page)
8530
        # assert data
8531
        image = page.asarray()
8532
        assert image.flags['C_CONTIGUOUS']
8533
        assert image.shape == (300, 400, 3)
8534
        assert image.dtype == numpy.uint8
8535
        assert tuple(image[124, 292]) == (236, 109, 95)
8536
        assert__str__(tif)
8537

8538

8539
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
8540
def test_read_subifd4():
8541
    """Test read BigTIFFSubIFD4."""
8542
    fname = public_file('twelvemonkeys/bigtiff/BigTIFFSubIFD4.tif')
8543
    with TiffFile(fname) as tif:
8544
        assert len(tif.series) == 1
8545
        assert len(tif.pages) == 2
8546
        page = tif.pages.first
8547
        assert page.photometric == PHOTOMETRIC.RGB
8548
        assert page.imagewidth == 64
8549
        assert page.imagelength == 64
8550
        assert page.bitspersample == 8
8551
        assert page.samplesperpixel == 3
8552
        assert page.tags['SubIFDs'].value == (3088,)
8553
        # assert subifd
8554
        page = page.pages[0]
8555
        assert page.photometric == PHOTOMETRIC.RGB
8556
        assert page.imagewidth == 32
8557
        assert page.imagelength == 32
8558
        assert page.bitspersample == 8
8559
        assert page.samplesperpixel == 3
8560
        # assert data
8561
        image = page.asarray()
8562
        assert image.flags['C_CONTIGUOUS']
8563
        assert image.shape == (32, 32, 3)
8564
        assert image.dtype == numpy.uint8
8565
        assert image[15, 15, 0] == 255
8566
        assert image[16, 16, 2] == 0
8567
        assert_aszarr_method(page)
8568
        assert__str__(tif)
8569

8570

8571
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
8572
def test_read_subifd8():
8573
    """Test read BigTIFFSubIFD8."""
8574
    fname = public_file('twelvemonkeys/bigtiff/BigTIFFSubIFD8.tif')
8575
    with TiffFile(fname) as tif:
8576
        assert len(tif.series) == 1
8577
        assert len(tif.pages) == 2
8578
        page = tif.pages.first
8579
        assert page.photometric == PHOTOMETRIC.RGB
8580
        assert page.imagewidth == 64
8581
        assert page.imagelength == 64
8582
        assert page.bitspersample == 8
8583
        assert page.samplesperpixel == 3
8584
        assert page.tags['SubIFDs'].value == (3088,)
8585
        # assert subifd
8586
        page = page.pages[0]
8587
        assert page.photometric == PHOTOMETRIC.RGB
8588
        assert page.imagewidth == 32
8589
        assert page.imagelength == 32
8590
        assert page.bitspersample == 8
8591
        assert page.samplesperpixel == 3
8592
        # assert data
8593
        image = page.asarray()
8594
        assert image.flags['C_CONTIGUOUS']
8595
        assert image.shape == (32, 32, 3)
8596
        assert image.dtype == numpy.uint8
8597
        assert image[15, 15, 0] == 255
8598
        assert image[16, 16, 2] == 0
8599
        assert_aszarr_method(page)
8600
        assert__str__(tif)
8601

8602

8603
@pytest.mark.skipif(
8604
    SKIP_CODECS or not imagecodecs.JPEG.available, reason=REASON
8605
)
8606
def test_read_tiles():
8607
    """Test iteration over tiles, manually and via page.segments."""
8608
    data = numpy.arange(600 * 500 * 3, dtype=numpy.uint8).reshape(
8609
        (600, 500, 3)
8610
    )
8611
    with TempFileName('read_tiles') as fname:
8612
        with TiffWriter(fname) as tif:
8613
            options = dict(
8614
                tile=(256, 256),
8615
                photometric=PHOTOMETRIC.RGB,
8616
                compression=COMPRESSION.JPEG,
8617
                metadata=None,
8618
            )
8619
            tif.write(data, **options)
8620
            tif.write(
8621
                data[::2, ::2], subfiletype=FILETYPE.REDUCEDIMAGE, **options
8622
            )
8623
        with TiffFile(fname) as tif:
8624
            fh = tif.filehandle
8625
            for page in tif.pages:
8626
                segments = page.segments()
8627
                jpegtables = page.tags.get('JPEGTables', None)
8628
                if jpegtables is not None:
8629
                    jpegtables = jpegtables.value
8630
                for index, (offset, bytecount) in enumerate(
8631
                    zip(page.dataoffsets, page.databytecounts)
8632
                ):
8633
                    fh.seek(offset)
8634
                    data = fh.read(bytecount)
8635
                    tile, indices, shape = page.decode(
8636
                        data, index, jpegtables=jpegtables
8637
                    )
8638
                    assert_array_equal(tile, next(segments)[0])
8639

8640

8641
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_LARGE, reason=REASON)
8642
def test_read_lsm_mosaic():
8643
    """Test read LSM: PTZCYX (Mosaic mode), two areas, 32 samples, >4 GB."""
8644
    # LSM files are little endian with two series, one of which is reduced RGB
8645
    # Tags may be unordered or contain bogus values
8646
    fname = private_file(
8647
        'lsm/Twoareas_Zstacks54slices_3umintervals_5cycles.lsm'
8648
    )
8649
    with TiffFile(fname) as tif:
8650
        assert tif.is_lsm
8651
        assert tif.byteorder == '<'
8652
        assert len(tif.pages) == 1080
8653
        assert len(tif.series) == 2
8654
        # assert page properties
8655
        page = tif.pages.first
8656
        assert page.is_lsm
8657
        assert page.is_contiguous
8658
        assert page.compression == COMPRESSION.NONE
8659
        assert page.imagewidth == 512
8660
        assert page.imagelength == 512
8661
        assert page.bitspersample == 16
8662
        assert page.samplesperpixel == 32
8663
        # assert strip offsets are corrected
8664
        page = tif.pages[-2]
8665
        assert page.dataoffsets[0] == 9070895981
8666
        # assert series properties
8667
        series = tif.series[0]
8668
        assert series.shape == (2, 5, 54, 32, 512, 512)
8669
        assert series.dtype == numpy.uint16
8670
        assert series.axes == 'PTZCYX'
8671
        assert series.kind == 'lsm'
8672
        if 1:
8673
            series = tif.series[1]
8674
            assert series.shape == (2, 5, 54, 3, 128, 128)
8675
            assert series.dtype == numpy.uint8
8676
            assert series.axes == 'PTZSYX'
8677
            assert series.kind == 'lsm'
8678
        # assert lsm_info tags
8679
        tags = tif.lsm_metadata
8680
        assert tags['DimensionX'] == 512
8681
        assert tags['DimensionY'] == 512
8682
        assert tags['DimensionZ'] == 54
8683
        assert tags['DimensionTime'] == 5
8684
        assert tags['DimensionChannels'] == 32
8685
        # assert lsm_scan_info tags
8686
        tags = tif.lsm_metadata['ScanInformation']
8687
        assert tags['ScanMode'] == 'Stack'
8688
        assert tags['User'] == 'lfdguest1'
8689
        # very slow: assert_aszarr_method(tif)
8690
        assert__str__(tif, 0)
8691

8692

8693
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_LARGE, reason=REASON)
8694
def test_read_lsm_carpet():
8695
    """Test read LSM: TYX (time series x-y), 72000 pages."""
8696
    # reads very slowly, ensure colormap is not applied
8697
    fname = private_file('lsm/Cardarelli_carpet_3.lsm')
8698
    with TiffFile(fname) as tif:
8699
        assert tif.is_lsm
8700
        assert tif.byteorder == '<'
8701
        assert len(tif.pages) == 72000
8702
        assert len(tif.series) == 2
8703
        # assert page properties
8704
        page = tif.pages.first
8705
        assert page.is_lsm
8706
        assert 'ColorMap' in page.tags
8707
        assert page.photometric == PHOTOMETRIC.PALETTE
8708
        assert page.compression == COMPRESSION.NONE
8709
        assert page.imagewidth == 32
8710
        assert page.imagelength == 10
8711
        assert page.bitspersample == 8
8712
        assert page.samplesperpixel == 1
8713
        # assert series properties
8714
        series = tif.series[0]
8715
        assert series.dtype == numpy.uint8
8716
        assert series.shape == (36000, 10, 32)
8717
        assert series.axes == 'TYX'
8718
        assert series.kind == 'lsm'
8719
        assert series.get_shape(False) == (36000, 1, 10, 32)
8720
        assert series.get_axes(False) == 'TCYX'
8721
        if 1:
8722
            series = tif.series[1]
8723
            assert series.dtype == numpy.uint8
8724
            assert series.shape == (36000, 3, 40, 128)
8725
            assert series.axes == 'TSYX'
8726
            assert series.get_shape(False) == (36000, 3, 40, 128)
8727
            assert series.get_axes(False) == 'TSYX'
8728
            assert series.kind == 'lsm'
8729
        # assert lsm_info tags
8730
        tags = tif.lsm_metadata
8731
        assert tags['DimensionX'] == 32
8732
        assert tags['DimensionY'] == 10
8733
        assert tags['DimensionZ'] == 1
8734
        assert tags['DimensionTime'] == 36000
8735
        assert tags['DimensionChannels'] == 1
8736
        # assert lsm_scan_info tags
8737
        tags = tif.lsm_metadata['ScanInformation']
8738
        assert tags['ScanMode'] == 'Plane'
8739
        assert tags['User'] == 'LSM User'
8740
        # assert_aszarr_method(tif)
8741
        assert__str__(tif, 0)
8742

8743

8744
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_LARGE, reason=REASON)
8745
def test_read_lsm_sfcs():
8746
    """Test read LSM linescan: TX (time series y), 1 page."""
8747
    # second page/series is corrupted: ImageLength=128 but StripByteCounts=1
8748

8749
    fname = private_file('lsm/sFCS_780_2069Hz_3p94us.lsm')
8750
    with TiffFile(fname) as tif:
8751
        assert tif.is_lsm
8752
        assert tif.byteorder == '<'
8753
        assert len(tif.pages) == 2
8754
        assert len(tif.series) == 2
8755
        # assert page properties
8756
        page = tif.pages.first
8757
        assert page.is_lsm
8758
        assert 'ColorMap' in page.tags
8759
        assert page.photometric == PHOTOMETRIC.PALETTE
8760
        assert page.compression == COMPRESSION.NONE
8761
        assert page.imagewidth == 52
8762
        assert page.imagelength == 100000
8763
        assert page.bitspersample == 16
8764
        assert page.samplesperpixel == 1
8765
        # assert series properties
8766
        series = tif.series[0]
8767
        assert series.dtype == numpy.uint16
8768
        assert series.shape == (100000, 52)
8769
        assert series.axes == 'TX'
8770
        assert series.kind == 'lsm'
8771
        assert series.get_shape(False) == (1, 1, 1, 100000, 52)
8772
        assert series.get_axes(False) == 'MPCTX'
8773
        data = series.asarray()
8774
        assert data.shape == (100000, 52)
8775
        assert data.dtype == numpy.uint16
8776
        assert data[1000].sum() == 4
8777

8778
        if 1:
8779
            series = tif.series[1]
8780
            assert series.dtype == numpy.uint8
8781
            assert series.shape == (3, 128, 1)
8782
            assert series.axes == 'SYX'
8783
            assert series.get_shape(False) == (3, 128, 1)
8784
            assert series.get_axes(False) == 'SYX'
8785
            assert series.kind == 'lsm'
8786
            with pytest.raises(TiffFileError):
8787
                # strip cannot be reshaped from (1,) to (1, 128, 1, 1)
8788
                series.asarray()
8789
        # assert lsm_info tags
8790
        tags = tif.lsm_metadata
8791
        assert tags['DimensionX'] == 52
8792
        assert tags['DimensionY'] == 1
8793
        assert tags['DimensionZ'] == 1
8794
        assert tags['DimensionTime'] == 100000
8795
        assert tags['DimensionChannels'] == 1
8796
        # assert lsm_scan_info tags
8797
        tags = tif.lsm_metadata['ScanInformation']
8798
        assert tags['ScanMode'] == 'Line'
8799
        assert tags['User'] == 'LSM User'
8800
        # assert_aszarr_method(tif)
8801
        assert__str__(tif, 0)
8802

8803

8804
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_LARGE, reason=REASON)
8805
def test_read_lsm_line_2channel():
8806
    """Test read LSM point scan with 2 channels: CTX, 1 page."""
8807
    # https://github.com/cgohlke/tifffile/issues/269
8808
    # second page/series is corrupted: ImageLength=128 but StripByteCounts=1
8809

8810
    fname = private_file('lsm/issue269.lsm')
8811
    with TiffFile(fname) as tif:
8812
        assert tif.is_lsm
8813
        assert tif.byteorder == '<'
8814
        assert len(tif.pages) == 2
8815
        assert len(tif.series) == 2
8816
        # assert page properties
8817
        page = tif.pages.first
8818
        assert page.is_lsm
8819
        assert 'ColorMap' not in page.tags
8820
        assert page.photometric == PHOTOMETRIC.RGB
8821
        assert page.compression == COMPRESSION.NONE
8822
        assert page.imagewidth == 512
8823
        assert page.imagelength == 70000
8824
        assert page.bitspersample == 8
8825
        assert page.samplesperpixel == 2
8826
        # assert series properties
8827
        series = tif.series[0]
8828
        assert series.dtype == numpy.uint8
8829
        assert series.shape == (2, 70000, 512)
8830
        assert series.axes == 'CTX'
8831
        assert series.kind == 'lsm'
8832
        assert series.get_axes(False) == 'MPCTX'
8833
        assert series.get_shape(False) == (1, 1, 2, 70000, 512)
8834
        data = series.asarray()
8835
        assert data.shape == (2, 70000, 512)
8836
        assert data.dtype == numpy.uint8
8837
        assert data[0, 1000].sum() == 13241
8838

8839
        if 1:
8840
            series = tif.series[1]
8841
            assert series.dtype == numpy.uint8
8842
            assert series.shape == (3, 128, 1)
8843
            assert series.axes == 'SYX'
8844
            assert series.get_shape(False) == (3, 128, 1)
8845
            assert series.get_axes(False) == 'SYX'
8846
            assert series.kind == 'lsm'
8847
            with pytest.raises(TiffFileError):
8848
                # strip cannot be reshaped from (1,) to (1, 128, 1, 1)
8849
                series.asarray()
8850
        # assert lsm_info tags
8851
        tags = tif.lsm_metadata
8852
        assert tags['DimensionX'] == 512
8853
        assert tags['DimensionY'] == 1
8854
        assert tags['DimensionZ'] == 1
8855
        assert tags['DimensionTime'] == 70000
8856
        assert tags['DimensionChannels'] == 2
8857
        # assert lsm_scan_info tags
8858
        tags = tif.lsm_metadata['ScanInformation']
8859
        assert tags['ScanMode'] == 'Line'
8860
        assert tags['User'] == 'LSMUser'
8861
        assert_aszarr_method(tif)
8862
        assert__str__(tif, 0)
8863

8864

8865
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
8866
def test_read_lsm_take1():
8867
    """Test read LSM: TZCYX (Plane mode), single image, uint8."""
8868
    fname = private_file('lsm/take1.lsm')
8869
    with TiffFile(fname) as tif:
8870
        assert tif.is_lsm
8871
        assert tif.byteorder == '<'
8872
        assert len(tif.pages) == 2
8873
        assert len(tif.series) == 2
8874
        # assert page properties
8875
        page = tif.pages.first
8876
        assert page.is_lsm
8877
        assert page.is_contiguous
8878
        assert page.compression == COMPRESSION.NONE
8879
        assert page.imagewidth == 512
8880
        assert page.imagelength == 512
8881
        assert page.bitspersample == 8
8882
        assert page.samplesperpixel == 1
8883
        page = tif.pages[1]
8884
        assert page.is_reduced
8885
        assert page.photometric == PHOTOMETRIC.RGB
8886
        assert page.planarconfig == PLANARCONFIG.SEPARATE
8887
        assert page.compression == COMPRESSION.NONE
8888
        assert page.imagewidth == 128
8889
        assert page.imagelength == 128
8890
        assert page.samplesperpixel == 3
8891
        assert page.bitspersample == 8
8892
        # assert series properties
8893
        series = tif.series[0]
8894
        assert series.dtype == numpy.uint8
8895
        assert series.shape == (512, 512)
8896
        assert series.axes == 'YX'
8897
        assert series.kind == 'lsm'
8898
        assert series.get_shape(False) == (1, 1, 512, 512)
8899
        assert series.get_axes(False) == 'ZCYX'
8900
        if 1:
8901
            series = tif.series[1]
8902
            assert series.shape == (3, 128, 128)
8903
            assert series.dtype == numpy.uint8
8904
            assert series.axes == 'SYX'
8905
            assert series.kind == 'lsm'
8906
        # assert data
8907
        data = tif.asarray()
8908
        assert isinstance(data, numpy.ndarray)
8909
        assert data.flags['C_CONTIGUOUS']
8910
        assert data.shape == (512, 512)
8911
        assert data.dtype == numpy.uint8
8912
        assert data[256, 256] == 101
8913
        if 1:
8914
            data = tif.asarray(series=1)
8915
            assert isinstance(data, numpy.ndarray)
8916
            assert data.shape == (3, 128, 128)
8917
            assert data.dtype == numpy.uint8
8918
            assert tuple(data[..., 64, 64]) == (89, 89, 89)
8919
        # assert lsm_info tags
8920
        tags = tif.lsm_metadata
8921
        assert tags['DimensionX'] == 512
8922
        assert tags['DimensionY'] == 512
8923
        assert tags['DimensionZ'] == 1
8924
        assert tags['DimensionTime'] == 1
8925
        assert tags['DimensionChannels'] == 1
8926
        # assert lsm_scan_info tags
8927
        tags = tif.lsm_metadata['ScanInformation']
8928
        assert tags['ScanMode'] == 'Plane'
8929
        assert tags['User'] == 'LSM User'
8930
        assert len(tags['Tracks']) == 1
8931
        assert len(tags['Tracks'][0]['DataChannels']) == 1
8932
        track = tags['Tracks'][0]
8933
        assert track['DataChannels'][0]['Name'] == 'Ch1'
8934
        assert track['DataChannels'][0]['BitsPerSample'] == 8
8935
        assert len(track['IlluminationChannels']) == 1
8936
        assert track['IlluminationChannels'][0]['Name'] == '561'
8937
        assert track['IlluminationChannels'][0]['Wavelength'] == 561.0
8938
        assert_aszarr_method(tif)
8939
        assert_aszarr_method(tif, series=1)
8940
        assert__str__(tif)
8941

8942

8943
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
8944
def test_read_lsm_2chzt():
8945
    """Test read LSM: ZCYX (Stack mode) uint8."""
8946
    fname = public_file('scif.io/2chZT.lsm')
8947
    with TiffFile(fname) as tif:
8948
        assert tif.is_lsm
8949
        assert tif.byteorder == '<'
8950
        assert len(tif.pages) == 798
8951
        assert len(tif.series) == 2
8952
        # assert page properties
8953
        page = tif.pages.first
8954
        assert page.is_lsm
8955
        assert page.is_contiguous
8956
        assert page.photometric == PHOTOMETRIC.RGB
8957
        assert page.tags['StripOffsets'].value[2] == 242632  # bogus offset
8958
        assert page.tags['StripByteCounts'].value[2] == 0  # no strip data
8959
        assert page.compression == COMPRESSION.NONE
8960
        assert page.imagewidth == 400
8961
        assert page.imagelength == 300
8962
        assert page.bitspersample == 8
8963
        assert page.samplesperpixel == 2
8964

8965
        page = tif.pages[1]
8966
        assert page.is_reduced
8967
        assert page.photometric == PHOTOMETRIC.RGB
8968
        assert page.planarconfig == PLANARCONFIG.SEPARATE
8969
        assert page.is_contiguous
8970
        assert page.compression == COMPRESSION.NONE
8971
        assert page.imagewidth == 128
8972
        assert page.imagelength == 96
8973
        assert page.samplesperpixel == 3
8974
        assert page.bitspersample == 8
8975
        # assert series properties
8976
        series = tif.series[0]
8977
        assert series.shape == (19, 21, 2, 300, 400)
8978
        assert series.dtype == numpy.uint8
8979
        assert series.axes == 'TZCYX'
8980
        assert series.kind == 'lsm'
8981
        if 1:
8982
            series = tif.series[1]
8983
            assert series.shape == (19, 21, 3, 96, 128)
8984
            assert series.dtype == numpy.uint8
8985
            assert series.axes == 'TZSYX'
8986
            assert series.kind == 'lsm'
8987
        # assert data
8988
        data = tif.asarray(out='memmap')
8989
        assert isinstance(data, numpy.memmap)
8990
        assert data.flags['C_CONTIGUOUS']
8991
        assert data.shape == (19, 21, 2, 300, 400)
8992
        assert data.dtype == numpy.uint8
8993
        assert data[18, 20, 1, 199, 299] == 39
8994
        if 1:
8995
            data = tif.asarray(series=1)
8996
            assert isinstance(data, numpy.ndarray)
8997
            assert data.shape == (19, 21, 3, 96, 128)
8998
            assert data.dtype == numpy.uint8
8999
            assert tuple(data[18, 20, :, 64, 96]) == (22, 22, 0)
9000
        del data
9001
        # assert lsm_info tags
9002
        tags = tif.lsm_metadata
9003
        assert tags['DimensionX'] == 400
9004
        assert tags['DimensionY'] == 300
9005
        assert tags['DimensionZ'] == 21
9006
        assert tags['DimensionTime'] == 19
9007
        assert tags['DimensionChannels'] == 2
9008
        # assert lsm_scan_info tags
9009
        tags = tif.lsm_metadata['ScanInformation']
9010
        assert tags['ScanMode'] == 'Stack'
9011
        assert tags['User'] == 'zjfhe'
9012
        assert len(tags['Tracks']) == 3
9013
        assert len(tags['Tracks'][0]['DataChannels']) == 1
9014
        track = tags['Tracks'][0]
9015
        assert track['DataChannels'][0]['Name'] == 'Ch3'
9016
        assert track['DataChannels'][0]['BitsPerSample'] == 8
9017
        assert len(track['IlluminationChannels']) == 6
9018
        assert track['IlluminationChannels'][5]['Name'] == '488'
9019
        assert track['IlluminationChannels'][5]['Wavelength'] == 488.0
9020
        assert_aszarr_method(tif)
9021
        assert_aszarr_method(tif, series=1)
9022
        assert__str__(tif, 0)
9023

9024

9025
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
9026
def test_read_lsm_unbounderror():
9027
    """Test read LSM: MZSYX (196, 2, 33, 512, 512)."""
9028
    # file is > 4GB with no time axis
9029
    fname = private_file('lsm/48h-CM-C-2.lsm')
9030
    with TiffFile(fname) as tif:
9031
        assert tif.is_lsm
9032
        assert tif.byteorder == '<'
9033
        assert len(tif.pages) == 784
9034
        assert len(tif.series) == 2
9035
        # assert page properties
9036
        page = tif.pages.first
9037
        assert page.is_lsm
9038
        assert page.is_contiguous
9039
        assert page.photometric == PHOTOMETRIC.RGB
9040
        assert page.planarconfig == PLANARCONFIG.SEPARATE
9041
        assert page.imagewidth == 512
9042
        assert page.imagelength == 512
9043
        assert page.bitspersample == 16
9044
        assert page.samplesperpixel == 33
9045
        page = tif.pages[1]
9046
        assert page.is_reduced
9047
        assert page.photometric == PHOTOMETRIC.RGB
9048
        assert page.planarconfig == PLANARCONFIG.SEPARATE
9049
        assert page.compression == COMPRESSION.NONE
9050
        assert page.imagewidth == 128
9051
        assert page.imagelength == 128
9052
        assert page.samplesperpixel == 3
9053
        assert page.bitspersample == 8
9054
        # assert series properties
9055
        series = tif.series[0]
9056
        assert series.shape == (196, 2, 33, 512, 512)
9057
        assert series.dtype == numpy.uint16
9058
        assert series.axes == 'MZCYX'
9059
        assert series.get_axes(False) == 'MPZCYX'
9060
        assert series.get_shape(False) == (196, 1, 2, 33, 512, 512)
9061
        assert series.kind == 'lsm'
9062
        if 1:
9063
            series = tif.series[1]
9064
            assert series.shape == (196, 2, 3, 128, 128)
9065
            assert series.dtype == numpy.uint8
9066
            assert series.axes == 'MZSYX'
9067
            assert series.get_axes(False) == 'MPZSYX'
9068
            assert series.get_shape(False) == (196, 1, 2, 3, 128, 128)
9069
            assert series.kind == 'lsm'
9070
        # assert data
9071
        data = tif.asarray()
9072
        assert isinstance(data, numpy.ndarray)
9073
        assert data.flags['C_CONTIGUOUS']
9074
        assert data.shape == (196, 2, 33, 512, 512)
9075
        assert data.dtype == numpy.uint16
9076
        assert data[195, 1, 32, 511, 511] == 22088
9077
        # assert_aszarr_method(tif, data)
9078
        if 1:
9079
            data = tif.asarray(series=1)
9080
            assert isinstance(data, numpy.ndarray)
9081
            assert data.shape == (196, 2, 3, 128, 128)
9082
            assert data.dtype == numpy.uint8
9083
            assert tuple(data[195, 1, :, 127, 127]) == (0, 61, 52)
9084
            # assert_aszarr_method(tif, series=1)
9085
        # assert lsm_info tags
9086
        tags = tif.lsm_metadata
9087
        assert tags['DimensionX'] == 512
9088
        assert tags['DimensionY'] == 512
9089
        assert tags['DimensionZ'] == 2
9090
        assert tags['DimensionTime'] == 1
9091
        assert tags['DimensionChannels'] == 33
9092
        # assert lsm_scan_info tags
9093
        tags = tif.lsm_metadata['ScanInformation']
9094
        assert tags['ScanMode'] == 'Stack'
9095
        assert tags['User'] == 'lfdguest1'
9096
        assert__str__(tif)
9097

9098

9099
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
9100
def test_read_lsm_incomplete(caplog):
9101
    """Test read LSM: MZSYX (196, 2, 33, 512, 512)."""
9102
    # file is ~18 GB incompletely written, dataoffsets zeroed
9103
    fname = private_file('lsm/NTERT_NM-50_x2.lsm')
9104

9105
    with TiffFile(fname) as tif:
9106
        assert 'LSM file incompletely written' in caplog.text
9107
        assert tif.is_lsm
9108
        assert tif.byteorder == '<'
9109
        assert len(tif.pages) == 2450
9110
        assert len(tif.series) == 2
9111
        # assert page properties
9112
        page = tif.pages.first
9113
        assert page.is_lsm
9114
        assert page.is_contiguous
9115
        assert page.photometric == PHOTOMETRIC.RGB
9116
        assert page.planarconfig == PLANARCONFIG.SEPARATE
9117
        assert page.imagewidth == 512
9118
        assert page.imagelength == 512
9119
        assert page.bitspersample == 16
9120
        assert page.samplesperpixel == 33
9121
        page = tif.pages[1]
9122
        assert page.is_reduced
9123
        assert page.photometric == PHOTOMETRIC.RGB
9124
        assert page.planarconfig == PLANARCONFIG.SEPARATE
9125
        assert page.compression == COMPRESSION.NONE
9126
        assert page.imagewidth == 128
9127
        assert page.imagelength == 128
9128
        assert page.samplesperpixel == 3
9129
        assert page.bitspersample == 8
9130
        # assert series properties
9131
        series = tif.series[0]
9132
        assert series.pages[-1].dataoffsets[0] == 0
9133
        assert series.shape == (25, 49, 33, 512, 512)
9134
        assert series.dtype == numpy.uint16
9135
        assert series.axes == 'MTCYX'
9136
        assert series.get_axes(False) == 'MPTCYX'
9137
        assert series.get_shape(False) == (25, 1, 49, 33, 512, 512)
9138
        assert series.kind == 'lsm'
9139
        if 1:
9140
            series = tif.series[1]
9141
            assert series.shape == (25, 49, 3, 128, 128)
9142
            assert series.get_shape(False) == (25, 1, 49, 3, 128, 128)
9143
            assert series.dtype == numpy.uint8
9144
            assert series.axes == 'MTSYX'
9145
            assert series.get_axes(False) == 'MPTSYX'
9146
            assert series.kind == 'lsm'
9147
        # assert data
9148
        data = tif.asarray()
9149
        assert isinstance(data, numpy.ndarray)
9150
        assert data.flags['C_CONTIGUOUS']
9151
        assert data.shape == (25, 49, 33, 512, 512)
9152
        assert data.dtype == numpy.uint16
9153
        assert data[24, 45, 32, 511, 511] == 14648
9154
        # assert_aszarr_method(tif, data)
9155
        if 1:
9156
            data = tif.asarray(series=1)
9157
            assert isinstance(data, numpy.ndarray)
9158
            assert data.shape == (25, 49, 3, 128, 128)
9159
            assert data.dtype == numpy.uint8
9160
            assert numpy.sum(data[24, 45]) == 0
9161
            # assert_aszarr_method(tif, series=1)
9162
        # assert lsm_info tags
9163
        tags = tif.lsm_metadata
9164
        assert tags['DimensionX'] == 512
9165
        assert tags['DimensionY'] == 512
9166
        assert tags['DimensionZ'] == 1
9167
        assert tags['DimensionTime'] == 49
9168
        assert tags['DimensionChannels'] == 33
9169
        # assert lsm_scan_info tags
9170
        tags = tif.lsm_metadata['ScanInformation']
9171
        assert tags['ScanMode'] == 'Plane'
9172
        assert tags['User'] == 'lfdguest1'
9173
        assert__str__(tif)
9174

9175

9176
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
9177
def test_read_lsm_earpax2isl11():
9178
    """Test read LSM: ZCYX (19, 3, 512, 512) uint8, RGB, LZW."""
9179
    fname = private_file('lsm/earpax2isl11.lzw.lsm')
9180
    with TiffFile(fname) as tif:
9181
        assert tif.is_lsm
9182
        assert tif.byteorder == '<'
9183
        assert len(tif.pages) == 38
9184
        assert len(tif.series) == 2
9185
        # assert page properties
9186
        page = tif.pages.first
9187
        assert page.is_lsm
9188
        assert not page.is_contiguous
9189
        assert page.photometric == PHOTOMETRIC.RGB
9190
        assert page.compression == COMPRESSION.LZW
9191
        assert page.imagewidth == 512
9192
        assert page.imagelength == 512
9193
        assert page.bitspersample == 8
9194
        assert page.samplesperpixel == 3
9195
        # assert corrected strip_byte_counts
9196
        assert page.tags['StripByteCounts'].value == (262144, 262144, 262144)
9197
        assert page.databytecounts == (131514, 192933, 167874)
9198
        page = tif.pages[1]
9199
        assert page.is_reduced
9200
        assert page.photometric == PHOTOMETRIC.RGB
9201
        assert page.planarconfig == PLANARCONFIG.SEPARATE
9202
        assert page.compression == COMPRESSION.NONE
9203
        assert page.imagewidth == 128
9204
        assert page.imagelength == 128
9205
        assert page.samplesperpixel == 3
9206
        assert page.bitspersample == 8
9207
        # assert series properties
9208
        series = tif.series[0]
9209
        assert series.shape == (19, 3, 512, 512)
9210
        assert series.dtype == numpy.uint8
9211
        assert series.axes == 'ZCYX'
9212
        assert series.get_axes(False) == 'ZCYX'
9213
        assert series.get_shape(False) == (19, 3, 512, 512)
9214
        assert series.kind == 'lsm'
9215
        if 1:
9216
            series = tif.series[1]
9217
            assert series.shape == (19, 3, 128, 128)
9218
            assert series.get_shape(False) == (19, 3, 128, 128)
9219
            assert series.dtype == numpy.uint8
9220
            assert series.axes == 'ZSYX'
9221
            assert series.get_axes(False) == 'ZSYX'
9222
            assert series.kind == 'lsm'
9223
        # assert data
9224
        data = tif.asarray()
9225
        assert isinstance(data, numpy.ndarray)
9226
        assert data.flags['C_CONTIGUOUS']
9227
        assert data.shape == (19, 3, 512, 512)
9228
        assert data.dtype == numpy.uint8
9229
        assert tuple(data[18, :, 200, 320]) == (17, 22, 21)
9230
        assert_aszarr_method(tif, data)
9231
        if 1:
9232
            data = tif.asarray(series=1)
9233
            assert isinstance(data, numpy.ndarray)
9234
            assert data.shape == (19, 3, 128, 128)
9235
            assert data.dtype == numpy.uint8
9236
            assert tuple(data[18, :, 64, 64]) == (25, 5, 33)
9237
            assert_aszarr_method(tif, series=1)
9238
        # assert lsm_info tags
9239
        tags = tif.lsm_metadata
9240
        assert tags['DimensionX'] == 512
9241
        assert tags['DimensionY'] == 512
9242
        assert tags['DimensionZ'] == 19
9243
        assert tags['DimensionTime'] == 1
9244
        assert tags['DimensionChannels'] == 3
9245
        # assert lsm_scan_info tags
9246
        tags = tif.lsm_metadata['ScanInformation']
9247
        assert tags['ScanMode'] == 'Stack'
9248
        assert tags['User'] == 'megason'
9249
        assert__str__(tif)
9250

9251

9252
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_CODECS or SKIP_LARGE, reason=REASON)
9253
def test_read_lsm_mb231paxgfp_060214():
9254
    """Test read LSM with many LZW compressed pages."""
9255
    # TZCYX (Stack mode), (60, 31, 2, 512, 512), 3720
9256
    fname = public_file('tifffile/MB231paxgfp_060214.lzw.lsm')
9257
    with TiffFile(fname) as tif:
9258
        assert tif.is_lsm
9259
        assert tif.byteorder == '<'
9260
        assert len(tif.pages) == 3720
9261
        assert len(tif.series) == 2
9262
        # assert page properties
9263
        page = tif.pages.first
9264
        assert page.is_lsm
9265
        assert not page.is_contiguous
9266
        assert page.compression == COMPRESSION.LZW
9267
        assert page.imagewidth == 512
9268
        assert page.imagelength == 512
9269
        assert page.bitspersample == 16
9270
        assert page.samplesperpixel == 2
9271
        page = tif.pages[1]
9272
        assert page.is_reduced
9273
        assert page.photometric == PHOTOMETRIC.RGB
9274
        assert page.planarconfig == PLANARCONFIG.SEPARATE
9275
        assert page.compression == COMPRESSION.NONE
9276
        assert page.imagewidth == 128
9277
        assert page.imagelength == 128
9278
        assert page.samplesperpixel == 3
9279
        assert page.bitspersample == 8
9280
        # assert series properties
9281
        series = tif.series[0]
9282
        assert series.dtype == numpy.uint16
9283
        assert series.shape == (60, 31, 2, 512, 512)
9284
        assert series.get_shape(False) == (60, 31, 2, 512, 512)
9285
        assert series.axes == 'TZCYX'
9286
        assert series.get_axes(False) == 'TZCYX'
9287
        assert series.kind == 'lsm'
9288
        if 1:
9289
            series = tif.series[1]
9290
            assert series.dtype == numpy.uint8
9291
            assert series.shape == (60, 31, 3, 128, 128)
9292
            assert series.axes == 'TZSYX'
9293
            assert series.kind == 'lsm'
9294
        # assert data
9295
        data = tif.asarray(out='memmap', maxworkers=None)
9296
        assert isinstance(data, numpy.memmap)
9297
        assert data.flags['C_CONTIGUOUS']
9298
        assert data.shape == (60, 31, 2, 512, 512)
9299
        assert data.dtype == numpy.dtype('<u2')
9300
        assert data[59, 30, 1, 256, 256] == 222
9301
        del data
9302
        # assert lsm_info tags
9303
        tags = tif.lsm_metadata
9304
        assert tags['DimensionX'] == 512
9305
        assert tags['DimensionY'] == 512
9306
        assert tags['DimensionZ'] == 31
9307
        assert tags['DimensionTime'] == 60
9308
        assert tags['DimensionChannels'] == 2
9309
        # assert some lsm_scan_info tags
9310
        tags = tif.lsm_metadata['ScanInformation']
9311
        assert tags['ScanMode'] == 'Stack'
9312
        assert tags['User'] == 'lfdguest1'
9313
        assert__str__(tif, 0)
9314

9315

9316
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_CODECS, reason=REASON)
9317
def test_read_lsm_lzw_no_eoi():
9318
    """Test read LSM with LZW compressed strip without EOI."""
9319
    # The first LZW compressed strip in page 834 has no EOI
9320
    # such that too much data is returned from the decoder and
9321
    # the data of the 2nd channel was getting corrupted
9322
    fname = public_file('tifffile/MB231paxgfp_060214.lzw.lsm')
9323
    with TiffFile(fname) as tif:
9324
        assert tif.is_lsm
9325
        assert tif.byteorder == '<'
9326
        assert len(tif.pages) == 3720
9327
        assert len(tif.series) == 2
9328
        # assert page properties
9329
        page = tif.pages.first
9330
        assert not page.is_contiguous
9331
        assert page.photometric == PHOTOMETRIC.RGB
9332
        assert page.compression == COMPRESSION.LZW
9333
        assert page.imagewidth == 512
9334
        assert page.imagelength == 512
9335
        assert page.bitspersample == 16
9336
        assert page.samplesperpixel == 2
9337
        page = tif.pages[834]
9338
        assert isinstance(page, TiffFrame)
9339
        assert page.dataoffsets == (344655101, 345109987)
9340
        assert page.databytecounts == (454886, 326318)
9341
        # assert second channel is not corrupted
9342
        data = page.asarray()
9343
        assert tuple(data[:, 0, 0]) == (288, 238)
9344
        assert__str__(tif, 0)
9345

9346

9347
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
9348
def test_stk_nonstack():
9349
    """Test read MetaMorph STK with single plane."""
9350
    # https://github.com/cgohlke/tifffile/pull/217
9351
    fname = private_file('stk/test_w1491-Fast_s1_t1.tif')
9352
    with TiffFile(fname) as tif:
9353
        assert tif.is_stk
9354
        assert tif.byteorder == '<'
9355
        assert len(tif.pages) == 1
9356
        assert len(tif.series) == 1
9357
        # assert page properties
9358
        page = tif.pages.first
9359
        assert page.is_contiguous
9360
        assert page.compression == COMPRESSION.NONE
9361
        assert page.imagewidth == 24
9362
        assert page.imagelength == 24
9363
        assert page.bitspersample == 16
9364
        assert page.samplesperpixel == 1
9365
        assert page.tags['Software'].value == 'MetaMorph 7.8.3.0'
9366
        assert page.tags['DateTime'].value == '2023:08:07 15:01:32'
9367
        assert page.datetime == datetime.datetime(2023, 8, 7, 15, 1, 32)
9368
        assert page.description.startswith('Exposure: 150 ms')
9369
        meta = stk_description_metadata(page.description)
9370
        assert meta[0]['Exposure'] == '150 ms'
9371
        # assert uic tags
9372
        tags = tif.stk_metadata
9373
        assert 'ZDistance' not in tags
9374
        assert 'Wavelengths' not in tags
9375
        assert tags['Name'] == '491_Fast'
9376
        assert tags['NumberPlanes'] == 1
9377
        assert ''.join(tags['StageLabel']) == 'position_a'
9378
        assert len(tags['AbsoluteZ']) == 1
9379
        assert tags['AbsoluteZ'][0] == 4294085.491
9380
        assert tuple(tags['StagePosition'][0]) == (16204.6, 444.7)
9381
        assert tuple(tags['CameraChipOffset'][0]) == (192.0, 219.0)
9382
        assert tags['PlaneDescriptions'][0].startswith('Exposure: 150 ms')
9383
        # assert series properties
9384
        series = tif.series[0]
9385
        assert not series.is_truncated
9386
        assert series.shape == (24, 24)
9387
        assert series.dtype == numpy.uint16
9388
        assert series.axes == 'YX'
9389
        assert series.kind == 'stk'
9390
        # assert data
9391
        data = tif.asarray()
9392
        assert isinstance(data, numpy.ndarray)
9393
        assert data.shape == (24, 24)
9394
        assert data.dtype == numpy.uint16
9395
        assert data[9, 11] == 3453
9396
        assert_aszarr_method(tif, data)
9397
        assert_decode_method(page)
9398
        assert__str__(tif)
9399

9400

9401
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
9402
def test_read_stk_zseries():
9403
    """Test read MetaMorph STK z-series."""
9404
    fname = private_file('stk/zseries.stk')
9405
    with TiffFile(fname) as tif:
9406
        assert tif.is_stk
9407
        assert tif.byteorder == '<'
9408
        assert len(tif.pages) == 1
9409
        assert len(tif.series) == 1
9410
        # assert page properties
9411
        page = tif.pages.first
9412
        assert page.is_contiguous
9413
        assert page.compression == COMPRESSION.NONE
9414
        assert page.imagewidth == 320
9415
        assert page.imagelength == 256
9416
        assert page.bitspersample == 16
9417
        assert page.samplesperpixel == 1
9418
        assert page.tags['Software'].value == 'MetaMorph'
9419
        assert page.tags['DateTime'].value == '2000:01:02 15:06:33'
9420
        assert page.datetime == datetime.datetime(2000, 1, 2, 15, 6, 33)
9421
        assert page.description.startswith('Acquired from MV-1500')
9422
        meta = stk_description_metadata(page.description)
9423
        assert meta[0]['Exposure'] == '2 ms'
9424
        # assert uic tags
9425
        tags = tif.stk_metadata
9426
        assert tags['Name'] == 'Z Series'
9427
        assert tags['NumberPlanes'] == 11
9428
        assert ''.join(tags['StageLabel']) == ''
9429
        assert tags['ZDistance'][10] == 2.5
9430
        assert len(tags['Wavelengths']) == 11
9431
        assert tags['Wavelengths'][10] == 490.0
9432
        assert len(tags['AbsoluteZ']) == 11
9433
        assert tags['AbsoluteZ'][10] == 150.0
9434
        assert tuple(tags['StagePosition'][10]) == (0.0, 0.0)
9435
        assert tuple(tags['CameraChipOffset'][10]) == (0.0, 0.0)
9436
        assert tags['PlaneDescriptions'][0].startswith('Acquired from MV-1500')
9437
        assert str(tags['DatetimeCreated'][0]) == (
9438
            '2000-02-02T15:06:02.000783000'
9439
        )
9440
        # assert series properties
9441
        series = tif.series[0]
9442
        assert series.is_truncated
9443
        assert series.shape == (11, 256, 320)
9444
        assert series.dtype == numpy.uint16
9445
        assert series.axes == 'ZYX'
9446
        assert series.kind == 'stk'
9447
        # assert data
9448
        data = tif.asarray()
9449
        assert isinstance(data, numpy.ndarray)
9450
        assert data.shape == (11, 256, 320)
9451
        assert data.dtype == numpy.uint16
9452
        assert data[8, 159, 255] == 1156
9453
        assert_aszarr_method(tif, data)
9454
        assert_decode_method(page)
9455
        assert__str__(tif)
9456

9457

9458
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
9459
def test_read_stk_zser24():
9460
    """Test read MetaMorph STK RGB z-series."""
9461
    fname = private_file('stk/zser24.stk')
9462
    with TiffFile(fname) as tif:
9463
        assert tif.is_stk
9464
        assert tif.byteorder == '<'
9465
        assert len(tif.pages) == 1
9466
        assert len(tif.series) == 1
9467
        # assert page properties
9468
        page = tif.pages.first
9469
        assert page.is_contiguous
9470
        assert page.photometric == PHOTOMETRIC.RGB
9471
        assert page.compression == COMPRESSION.NONE
9472
        assert page.imagewidth == 160
9473
        assert page.imagelength == 128
9474
        assert page.bitspersample == 8
9475
        assert page.samplesperpixel == 3
9476
        assert page.tags['Software'].value == 'MetaMorph'
9477
        assert page.tags['DateTime'].value == '2000:01:02 15:11:23'
9478
        # assert uic tags
9479
        tags = tif.stk_metadata
9480
        assert tags['Name'] == 'Color Encoded'
9481
        assert tags['NumberPlanes'] == 11
9482
        assert ''.join(tags['StageLabel']) == ''
9483
        assert tags['ZDistance'][10] == 2.5
9484
        assert len(tags['Wavelengths']) == 11
9485
        assert tags['Wavelengths'][10] == 510.0
9486
        assert len(tags['AbsoluteZ']) == 11
9487
        assert tags['AbsoluteZ'][10] == 150.0
9488
        assert tuple(tags['StagePosition'][10]) == (0.0, 0.0)
9489
        assert tuple(tags['CameraChipOffset'][10]) == (320.0, 256.0)
9490
        assert str(tags['DatetimeCreated'][0]) == (
9491
            '2000-02-02T15:10:34.000264000'
9492
        )
9493
        # assert series properties
9494
        series = tif.series[0]
9495
        assert series.is_truncated
9496
        assert series.shape == (11, 128, 160, 3)
9497
        assert series.dtype == numpy.uint8
9498
        assert series.axes == 'ZYXS'
9499
        assert series.kind == 'stk'
9500
        # assert data
9501
        data = tif.asarray()
9502
        assert isinstance(data, numpy.ndarray)
9503
        assert data.shape == (11, 128, 160, 3)
9504
        assert data.dtype == numpy.uint8
9505
        assert tuple(data[8, 100, 135]) == (70, 63, 0)
9506
        assert_aszarr_method(tif, data)
9507
        assert_decode_method(page)
9508
        assert__str__(tif)
9509

9510

9511
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
9512
def test_read_stk_diatoms3d():
9513
    """Test read MetaMorph STK time-series."""
9514
    fname = private_file('stk/diatoms3d.stk')
9515
    with TiffFile(fname) as tif:
9516
        assert tif.is_stk
9517
        assert tif.byteorder == '<'
9518
        assert len(tif.pages) == 1
9519
        assert len(tif.series) == 1
9520
        # assert page properties
9521
        page = tif.pages.first
9522
        assert page.is_contiguous
9523
        assert page.compression == COMPRESSION.NONE
9524
        assert page.imagewidth == 196
9525
        assert page.imagelength == 191
9526
        assert page.bitspersample == 8
9527
        assert page.samplesperpixel == 1
9528
        assert page.tags['Software'].value == 'MetaMorph'
9529
        assert page.tags['DateTime'].value == '2000:01:04 14:57:22'
9530
        # assert uic tags
9531
        tags = tif.stk_metadata
9532
        assert tags['Name'] == 'diatoms3d'
9533
        assert tags['NumberPlanes'] == 10
9534
        assert ''.join(tags['StageLabel']) == ''
9535
        assert tags['ZDistance'][9] == 3.54545
9536
        assert len(tags['Wavelengths']) == 10
9537
        assert tags['Wavelengths'][9] == 440.0
9538
        assert len(tags['AbsoluteZ']) == 10
9539
        assert tags['AbsoluteZ'][9] == 12898.15
9540
        assert tuple(tags['StagePosition'][9]) == (0.0, 0.0)
9541
        assert tuple(tags['CameraChipOffset'][9]) == (206.0, 148.0)
9542
        assert tags['PlaneDescriptions'][0].startswith(
9543
            'Acquired from Flashbus.'
9544
        )
9545
        assert str(tags['DatetimeCreated'][0]) == (
9546
            '2000-02-04T14:38:37.000738000'
9547
        )
9548
        # assert series properties
9549
        series = tif.series[0]
9550
        assert series.shape == (10, 191, 196)
9551
        assert series.dtype == numpy.uint8
9552
        assert series.axes == 'ZYX'
9553
        assert series.kind == 'stk'
9554
        # assert data
9555
        data = tif.asarray()
9556
        assert isinstance(data, numpy.ndarray)
9557
        assert data.shape == (10, 191, 196)
9558
        assert data.dtype == numpy.uint8
9559
        assert data[8, 100, 135] == 223
9560
        assert_aszarr_method(tif, data)
9561
        assert_decode_method(page)
9562
        assert__str__(tif)
9563

9564

9565
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
9566
def test_read_stk_greenbeads():
9567
    """Test read MetaMorph STK time-series, but time_created is corrupt (?)."""
9568
    # 8bit palette is present but should not be applied
9569
    fname = private_file('stk/GreenBeads.stk')
9570
    with TiffFile(fname) as tif:
9571
        assert tif.is_stk
9572
        assert tif.byteorder == '<'
9573
        assert len(tif.pages) == 1
9574
        assert len(tif.series) == 1
9575
        # assert page properties
9576
        page = tif.pages.first
9577
        assert page.is_contiguous
9578
        assert page.photometric == PHOTOMETRIC.PALETTE
9579
        assert page.compression == COMPRESSION.NONE
9580
        assert page.imagewidth == 298
9581
        assert page.imagelength == 322
9582
        assert page.bitspersample == 8
9583
        assert page.samplesperpixel == 1
9584
        assert page.tags['Software'].value == 'MetaMorph 7.5.3.0'
9585
        assert page.tags['DateTime'].value == '2008:05:09 17:35:32'
9586
        # assert uic tags
9587
        tags = tif.stk_metadata
9588
        assert tags['Name'] == 'Green'
9589
        assert tags['NumberPlanes'] == 79
9590
        assert tags['ZDistance'][1] == 0.0
9591
        assert len(tags['Wavelengths']) == 79
9592
        assert tuple(tags['CameraChipOffset'][0]) == (0.0, 0.0)
9593
        assert str(tags['DatetimeModified'][0]) == (
9594
            '2008-05-09T17:35:33.000274000'
9595
        )
9596
        # assert tags['AbsoluteZ'][78] == 1.1672684733218932
9597
        assert 'AbsoluteZ' not in tags
9598
        # assert series properties
9599
        series = tif.series[0]
9600
        assert series.shape == (79, 322, 298)
9601
        assert series.dtype == numpy.uint8
9602
        assert series.axes == 'IYX'  # corrupt time_created
9603
        assert series.kind == 'stk'
9604
        # assert data
9605
        data = tif.asarray()
9606
        assert isinstance(data, numpy.ndarray)
9607
        assert data.shape == (79, 322, 298)
9608
        assert data.dtype == numpy.uint8
9609
        assert data[43, 180, 102] == 205
9610
        assert_aszarr_method(tif, data)
9611
        assert__str__(tif)
9612

9613

9614
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
9615
def test_read_stk_10xcalib():
9616
    """Test read MetaMorph STK two planes, not Z or T series."""
9617
    fname = private_file('stk/10xcalib.stk')
9618
    with TiffFile(fname) as tif:
9619
        assert tif.is_stk
9620
        assert tif.byteorder == '<'
9621
        assert len(tif.pages) == 1
9622
        assert len(tif.series) == 1
9623
        # assert page properties
9624
        page = tif.pages.first
9625
        assert page.is_contiguous
9626
        assert page.photometric != PHOTOMETRIC.PALETTE
9627
        assert page.compression == COMPRESSION.NONE
9628
        assert page.imagewidth == 640
9629
        assert page.imagelength == 480
9630
        assert page.bitspersample == 8
9631
        assert page.samplesperpixel == 1
9632
        assert page.tags['Software'].value == 'MetaMorph'
9633
        assert page.tags['DateTime'].value == '2000:03:28 09:24:37'
9634
        # assert uic tags
9635
        tags = tif.stk_metadata
9636
        assert tags['Name'] == '10xcalib'
9637
        assert tags['NumberPlanes'] == 2
9638
        assert tuple(tags['Wavelengths']) == (440.0, 440.0)
9639
        assert tags['XCalibration'] == 1.24975007
9640
        assert tags['YCalibration'] == 1.24975007
9641
        # assert series properties
9642
        series = tif.series[0]
9643
        assert series.shape == (2, 480, 640)
9644
        assert series.dtype == numpy.uint8
9645
        assert series.axes == 'IYX'
9646
        assert series.kind == 'stk'
9647
        # assert data
9648
        data = tif.asarray()
9649
        assert isinstance(data, numpy.ndarray)
9650
        assert data.shape == (2, 480, 640)
9651
        assert data.dtype == numpy.uint8
9652
        assert data[1, 339, 579] == 56
9653
        assert_aszarr_method(tif, data)
9654
        assert__str__(tif)
9655

9656

9657
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_LARGE, reason=REASON)
9658
def test_read_stk_112508h100():
9659
    """Test read MetaMorph STK large time-series."""
9660
    fname = private_file('stk/112508h100.stk')
9661
    with TiffFile(fname) as tif:
9662
        assert tif.is_stk
9663
        assert tif.byteorder == '<'
9664
        assert len(tif.pages) == 1
9665
        assert len(tif.series) == 1
9666
        # assert page properties
9667
        page = tif.pages.first
9668
        assert page.is_contiguous
9669
        assert page.photometric != PHOTOMETRIC.PALETTE
9670
        assert page.compression == COMPRESSION.NONE
9671
        assert page.imagewidth == 512
9672
        assert page.imagelength == 128
9673
        assert page.bitspersample == 16
9674
        assert page.samplesperpixel == 1
9675
        assert page.tags['Software'].value == 'MetaMorph 7.5.3.0'
9676
        assert page.tags['DateTime'].value == '2008:11:25 18:59:20'
9677
        # assert uic tags
9678
        tags = tif.stk_metadata
9679
        assert tags['Name'] == 'Photometrics'
9680
        assert tags['NumberPlanes'] == 2048
9681
        assert len(tags['PlaneDescriptions']) == 2048
9682
        assert tags['PlaneDescriptions'][0].startswith(
9683
            'Acquired from Photometrics\r\n'
9684
        )
9685
        assert tags['CalibrationUnits'] == 'pixel'
9686
        # assert series properties
9687
        series = tif.series[0]
9688
        assert series.shape == (2048, 128, 512)
9689
        assert series.dtype == numpy.uint16
9690
        assert series.axes == 'TYX'
9691
        assert series.kind == 'stk'
9692
        # assert data
9693
        data = tif.asarray()
9694
        assert isinstance(data, numpy.ndarray)
9695
        assert data.shape == (2048, 128, 512)
9696
        assert data.dtype == numpy.uint16
9697
        assert data[2047, 64, 128] == 7132
9698
        assert_aszarr_method(tif, data)
9699
        assert__str__(tif)
9700

9701

9702
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_LARGE, reason=REASON)
9703
def test_read_stk_noname():
9704
    """Test read MetaMorph STK with no name in metadata."""
9705
    # https://forum.image.sc/t/metamorph-stack-issue-with-ome-metadata-
9706
    # bioformats-and-omero/48416
9707
    fname = private_file('stk/60x_2well_diffexpos1_w1sdcGFP_s1_t1.stk')
9708
    with TiffFile(fname) as tif:
9709
        assert tif.is_stk
9710
        assert tif.byteorder == '<'
9711
        assert len(tif.pages) == 1
9712
        assert len(tif.series) == 1
9713
        # assert page properties
9714
        page = tif.pages.first
9715
        assert page.is_contiguous
9716
        assert page.photometric == PHOTOMETRIC.MINISBLACK
9717
        assert page.compression == COMPRESSION.NONE
9718
        assert page.imagewidth == 1148
9719
        assert page.imagelength == 1112
9720
        assert page.bitspersample == 16
9721
        assert page.samplesperpixel == 1
9722
        assert page.tags['Software'].value == 'VisiView 4.5.0'
9723
        assert page.tags['DateTime'].value == '2021:01:27 13:29:51'
9724
        # assert uic tags
9725
        tags = tif.stk_metadata
9726
        assert 'Name' not in tags
9727
        assert tags['NumberPlanes'] == 5
9728
        assert len(tags['PlaneDescriptions']) == 5
9729
        assert tags['PlaneDescriptions'][0].startswith('Exposure: 50 ms\r\n')
9730
        # assert series properties
9731
        series = tif.series[0]
9732
        assert series.shape == (5, 1112, 1148)
9733
        assert series.dtype == numpy.uint16
9734
        assert series.axes == 'ZYX'
9735
        assert series.kind == 'stk'
9736
        # assert data
9737
        data = tif.asarray()
9738
        assert isinstance(data, numpy.ndarray)
9739
        assert data.shape == (5, 1112, 1148)
9740
        assert data.dtype == numpy.uint16
9741
        assert data[4, 64, 128] == 98
9742
        assert_aszarr_method(tif, data)
9743
        assert__str__(tif)
9744

9745

9746
@pytest.mark.skipif(
9747
    SKIP_PRIVATE or SKIP_CODECS or not imagecodecs.JPEG.available,
9748
    reason=REASON,
9749
)
9750
def test_read_ndpi_cmu1():
9751
    """Test read Hamamatsu NDPI slide, JPEG."""
9752
    fname = private_file('HamamatsuNDPI/CMU-1.ndpi')
9753
    with TiffFile(fname) as tif:
9754
        assert tif.is_ndpi
9755
        assert len(tif.pages) == 5
9756
        assert len(tif.series) == 2
9757
        for page in tif.pages:
9758
            assert page.ndpi_tags['Model'] == 'NanoZoomer'
9759
        # first page
9760
        page = tif.pages.first
9761
        assert page.is_ndpi
9762
        assert page.photometric == PHOTOMETRIC.YCBCR
9763
        assert page.compression == COMPRESSION.JPEG
9764
        assert page.shape == (38144, 51200, 3)
9765
        assert page.ndpi_tags['Magnification'] == 20.0
9766
        # page 4
9767
        page = tif.pages[4]
9768
        assert page.is_ndpi
9769
        assert page.photometric == PHOTOMETRIC.YCBCR
9770
        assert page.compression == COMPRESSION.JPEG
9771
        assert page.shape == (408, 1191, 3)
9772
        assert page.ndpi_tags['Magnification'] == -1.0
9773
        assert page.asarray()[226, 629, 0] == 167
9774
        assert_aszarr_method(page)
9775
        assert__str__(tif)
9776

9777

9778
@pytest.mark.skipif(
9779
    SKIP_PRIVATE
9780
    or SKIP_CODECS
9781
    or SKIP_LARGE
9782
    or not imagecodecs.JPEG.available,
9783
    reason=REASON,
9784
)
9785
def test_read_ndpi_cmu2():
9786
    """Test read Hamamatsu NDPI slide, JPEG."""
9787
    # JPEG stream too large to be opened with unpatched libjpeg
9788
    fname = private_file('HamamatsuNDPI/CMU-2.ndpi')
9789
    with TiffFile(fname) as tif:
9790
        assert tif.is_ndpi
9791
        assert len(tif.pages) == 6
9792
        assert len(tif.series) == 2
9793
        for page in tif.pages:
9794
            assert page.ndpi_tags['Model'] == 'NanoZoomer'
9795
        # first page
9796
        page = tif.pages.first
9797
        assert page.is_ndpi
9798
        assert page.photometric == PHOTOMETRIC.YCBCR
9799
        assert page.compression == COMPRESSION.JPEG
9800
        assert page.shape == (33792, 79872, 3)
9801
        assert page.ndpi_tags['Magnification'] == 20.0
9802
        # with pytest.raises(RuntimeError):
9803
        if not IS_PYPY:
9804
            data = page.asarray()
9805
            assert data.shape == (33792, 79872, 3)
9806
            assert data.dtype == numpy.uint8
9807
        # page 5
9808
        page = tif.pages[5]
9809
        assert page.is_ndpi
9810
        assert page.photometric == PHOTOMETRIC.YCBCR
9811
        assert page.compression == COMPRESSION.JPEG
9812
        assert page.shape == (408, 1191, 3)
9813
        assert page.ndpi_tags['Magnification'] == -1.0
9814
        assert page.asarray()[226, 629, 0] == 181
9815
        assert_aszarr_method(page)
9816
        assert__str__(tif)
9817

9818

9819
@pytest.mark.skipif(
9820
    SKIP_LARGE
9821
    or SKIP_PRIVATE
9822
    or SKIP_CODECS
9823
    or not imagecodecs.JPEG.available,
9824
    reason=REASON,
9825
)
9826
def test_read_ndpi_4gb():
9827
    """Test read > 4 GB Hamamatsu NDPI slide, JPEG 103680x188160."""
9828
    fname = private_file('HamamatsuNDPI/103680x188160.ndpi')
9829
    with TiffFile(fname) as tif:
9830
        assert tif.is_ndpi
9831
        assert len(tif.pages) == 8
9832
        assert len(tif.series) == 3
9833
        for page in tif.pages:
9834
            assert page.ndpi_tags['Model'] == 'C13220'
9835
        # first page
9836
        page = tif.pages.first
9837
        assert page.offset == 4466602683
9838
        assert page.is_ndpi
9839
        assert page.databytecounts[0] == 5105  # not 4461521316
9840
        assert page.photometric == PHOTOMETRIC.YCBCR
9841
        assert page.compression == COMPRESSION.JPEG
9842
        assert page.shape == (103680, 188160, 3)
9843
        assert (
9844
            page.tags['ImageLength'].offset - page.tags['ImageWidth'].offset
9845
            == 12
9846
        )
9847
        assert page.tags['ImageWidth'].offset == 4466602685
9848
        assert page.tags['ImageWidth'].valueoffset == 4466602693
9849
        assert page.tags['ImageLength'].offset == 4466602697
9850
        assert page.tags['ImageLength'].valueoffset == 4466602705
9851
        assert page.tags['ReferenceBlackWhite'].offset == 4466602889
9852
        assert page.tags['ReferenceBlackWhite'].valueoffset == 1003
9853
        assert page.ndpi_tags['Magnification'] == 40.0
9854
        assert page.ndpi_tags['McuStarts'][-1] == 4461516507  # corrected
9855
        with pytest.raises(ValueError):
9856
            page.tags['StripByteCounts'].astuple()
9857
        if not SKIP_ZARR:
9858
            # data = page.asarray()  # 55 GB
9859
            with page.aszarr() as store:
9860
                data = zarr.open(store, mode='r')
9861
                assert data[38061, 121978].tolist() == [220, 167, 187]
9862
        # page 7
9863
        page = tif.pages[7]
9864
        assert page.is_ndpi
9865
        assert page.photometric == PHOTOMETRIC.MINISBLACK
9866
        assert page.compression == COMPRESSION.NONE
9867
        assert page.shape == (200, 600)
9868
        assert page.ndpi_tags['Magnification'] == -2.0
9869
        # assert page.asarray()[226, 629, 0] == 167
9870
        # first series
9871
        series = tif.series[0]
9872
        assert series.kind == 'ndpi'
9873
        assert series.name == 'S10533009'
9874
        assert series.shape == (103680, 188160, 3)
9875
        assert series.is_pyramidal
9876
        assert len(series.levels) == 6
9877
        assert len(series.pages) == 1
9878
        # pyramid levels
9879
        assert series.levels[1].shape == (51840, 94080, 3)
9880
        assert series.levels[2].shape == (25920, 47040, 3)
9881
        assert series.levels[3].shape == (12960, 23520, 3)
9882
        assert series.levels[4].shape == (6480, 11760, 3)
9883
        assert series.levels[5].shape == (3240, 5880, 3)
9884
        data = series.levels[5].asarray()
9885
        assert tuple(data[1000, 1000]) == (222, 165, 200)
9886
        with pytest.raises(ValueError):
9887
            page.tags['StripOffsets'].astuple()
9888
        # cannot decode base levels since JPEG compressed size > 2 GB
9889
        # series.levels[0].asarray()
9890
        assert_aszarr_method(series.levels[5], data)
9891
        assert__str__(tif)
9892

9893

9894
@pytest.mark.skipif(
9895
    SKIP_PRIVATE or SKIP_CODECS or not imagecodecs.JPEGXR.available,
9896
    reason=REASON,
9897
)
9898
def test_read_ndpi_jpegxr():
9899
    """Test read Hamamatsu NDPI slide with JPEG XR compression."""
9900
    # https://downloads.openmicroscopy.org/images/Hamamatsu-NDPI/hamamatsu/
9901
    fname = private_file('HamamatsuNDPI/DM0014 - 2020-04-02 10.25.21.ndpi')
9902
    with TiffFile(fname) as tif:
9903
        assert tif.is_ndpi
9904
        assert len(tif.pages) == 6
9905
        assert len(tif.series) == 3
9906
        for page in tif.pages:
9907
            assert page.ndpi_tags['Model'] == 'C13210'
9908

9909
        for page in tif.pages[:4]:
9910
            # check that all levels are corrected
9911
            assert page.is_ndpi
9912
            assert (
9913
                page.tags['PhotometricInterpretation'].value
9914
                == PHOTOMETRIC.YCBCR
9915
            )
9916
            assert page.tags['BitsPerSample'].value == (8, 8, 8)
9917
            assert page.samplesperpixel == 1  # not 3
9918
            assert page.bitspersample == 16  # not 8
9919
            assert page.photometric == PHOTOMETRIC.MINISBLACK  # not YCBCR
9920
            assert page.compression == COMPRESSION.JPEGXR_NDPI
9921

9922
        # first page
9923
        page = tif.pages.first
9924
        assert page.shape == (34944, 69888)  # not (34944, 69888, 3)
9925
        assert page.databytecounts[0] == 632009
9926
        assert page.ndpi_tags['CaptureMode'] == 17
9927
        assert page.ndpi_tags['Magnification'] == 20.0
9928
        if not SKIP_ZARR:
9929
            with page.aszarr() as store:
9930
                data = zarr.open(store, mode='r')
9931
                assert data[28061, 41978] == 6717
9932
        # page 5
9933
        page = tif.pages[5]
9934
        assert page.is_ndpi
9935
        assert page.photometric == PHOTOMETRIC.MINISBLACK
9936
        assert page.compression == COMPRESSION.NONE
9937
        assert page.shape == (192, 566)
9938
        assert page.ndpi_tags['Magnification'] == -2.0
9939
        # first series
9940
        series = tif.series[0]
9941
        assert series.kind == 'ndpi'
9942
        assert series.name == 'DM0014'
9943
        assert series.shape == (34944, 69888)
9944
        assert series.is_pyramidal
9945
        assert len(series.levels) == 4
9946
        assert len(series.pages) == 1
9947
        # pyramid levels
9948
        assert series.levels[1].shape == (17472, 34944)
9949
        assert series.levels[2].shape == (8736, 17472)
9950
        assert series.levels[3].shape == (4368, 8736)
9951
        data = series.levels[3].asarray()
9952
        assert data[1000, 1000] == 1095
9953
        assert_aszarr_method(series.levels[3], data)
9954
        assert__str__(tif)
9955

9956

9957
@pytest.mark.skipif(
9958
    SKIP_PRIVATE
9959
    or SKIP_LARGE
9960
    or SKIP_CODECS
9961
    or not imagecodecs.JPEG.available,
9962
    reason=REASON,
9963
)
9964
def test_read_ndpi_databytecounts():
9965
    """Test read Hamamatsu NDPI slide databytecounts do not overflow."""
9966
    # https://forum.image.sc/t/some-ndpi-files-not-opening-in-qupath-v0-4-1
9967
    fname = private_file('HamamatsuNDPI/doesnt_work.ndpi')
9968
    with TiffFile(fname) as tif:
9969
        assert tif.is_ndpi
9970
        assert len(tif.pages) == 23
9971
        assert len(tif.series) == 3
9972
        # first series
9973
        series = tif.series[0]
9974
        assert series.kind == 'ndpi'
9975
        assert series.name == 'Baseline'
9976
        assert series.shape == (3, 60928, 155648, 3)
9977
        assert series.is_pyramidal
9978
        assert len(series.levels) == 7
9979
        assert len(series.pages) == 3
9980
        # pyramid levels
9981
        assert series.levels[1].shape == (3, 30464, 77824, 3)
9982
        assert series.levels[2].shape == (3, 15232, 38912, 3)
9983
        assert series.levels[3].shape == (3, 7616, 19456, 3)
9984
        assert series.levels[4].shape == (3, 3808, 9728, 3)
9985
        assert series.levels[5].shape == (3, 1904, 4864, 3)
9986
        assert series.levels[6].shape == (3, 952, 2432, 3)
9987
        # 3rd z-slice in base layer
9988
        page = series.pages[2]
9989
        assert page.index == 14
9990
        assert page.shape == (60928, 155648, 3)
9991
        assert page.dataoffsets[-1] == 4718518695
9992
        assert page.databytecounts[-1] == 4338
9993
        assert page.ndpi_tags['Magnification'] == 40.0
9994
        assert page.ndpi_tags['FocusTime'] == 13
9995
        assert page.ndpi_tags['ScannerSerialNumber'] == '680057'
9996
        assert tuple(page.asarray()[60000, 150000]) == (216, 221, 217)
9997

9998

9999
@pytest.mark.skipif(
10000
    SKIP_PRIVATE or SKIP_CODECS or not imagecodecs.JPEG.available,
10001
    reason=REASON,
10002
)
10003
def test_read_ndpi_layers():
10004
    """Test read Hamamatsu NDPI slide with 5 layers."""
10005
    fname = private_file('HamamatsuNDPI/hamamatsu_5-layers.ndpi')
10006
    with TiffFile(fname) as tif:
10007
        assert tif.is_ndpi
10008
        assert len(tif.pages) == 37
10009
        assert len(tif.series) == 3
10010
        for page in tif.pages:
10011
            assert page.ndpi_tags['Model'] == 'C10730-12'
10012

10013
        for page in tif.pages[:4]:
10014
            assert page.is_ndpi
10015
            assert (
10016
                page.tags['PhotometricInterpretation'].value
10017
                == PHOTOMETRIC.YCBCR
10018
            )
10019
            assert page.tags['BitsPerSample'].value == (8, 8, 8)
10020
            assert page.samplesperpixel == 3
10021
            assert page.bitspersample == 8
10022
            assert page.photometric == PHOTOMETRIC.YCBCR
10023
            assert page.compression == COMPRESSION.JPEG
10024

10025
        # first page
10026
        page = tif.pages.first
10027
        assert page.shape == (12032, 11520, 3)
10028
        assert page.databytecounts[0] == 1634
10029
        assert page.ndpi_tags['CaptureMode'] == 0
10030
        assert page.ndpi_tags['Magnification'] == 20.0
10031
        if not SKIP_ZARR:
10032
            with page.aszarr() as store:
10033
                data = zarr.open(store, mode='r')
10034
                assert list(data[10000, 10000]) == [232, 215, 225]
10035
        # last page
10036
        page = tif.pages[-1]
10037
        assert page.is_ndpi
10038
        assert page.photometric == PHOTOMETRIC.MINISBLACK
10039
        assert page.compression == COMPRESSION.NONE
10040
        assert page.shape == (196, 575)
10041
        assert page.ndpi_tags['Magnification'] == -2.0
10042
        # first series
10043
        series = tif.series[0]
10044
        assert series.kind == 'ndpi'
10045
        assert series.name == 'Baseline'
10046
        assert series.shape == (7, 12032, 11520, 3)
10047
        assert series.is_pyramidal
10048
        assert len(series.levels) == 5
10049
        assert len(series.pages) == 7
10050
        # pyramid levels
10051
        assert series.levels[1].shape == (7, 6016, 5760, 3)
10052
        assert series.levels[2].shape == (7, 3008, 2880, 3)
10053
        assert series.levels[3].shape == (7, 1504, 1440, 3)
10054
        assert series.levels[4].shape == (7, 752, 720, 3)
10055
        data = series.levels[3].asarray()
10056
        assert_array_equal(
10057
            data[:, 1000, 1000],
10058
            [
10059
                [234, 217, 225],
10060
                [231, 213, 225],
10061
                [233, 215, 227],
10062
                [234, 217, 225],
10063
                [234, 216, 228],
10064
                [233, 216, 224],
10065
                [232, 214, 226],
10066
            ],
10067
        )
10068
        assert_aszarr_method(series.levels[3], data)
10069
        assert__str__(tif)
10070

10071

10072
@pytest.mark.skipif(
10073
    SKIP_PRIVATE or SKIP_CODECS or not imagecodecs.JPEG.available,
10074
    reason=REASON,
10075
)
10076
def test_read_svs_cmu1():
10077
    """Test read Aperio SVS slide, JPEG and LZW."""
10078
    fname = private_file('AperioSVS/CMU-1.svs')
10079
    with TiffFile(fname) as tif:
10080
        assert tif.is_svs
10081
        assert not tif.is_scanimage
10082
        assert len(tif.pages) == 6
10083
        assert len(tif.series) == 4
10084
        for page in tif.pages:
10085
            svs_description_metadata(page.description)
10086
        # first page
10087
        page = tif.pages.first
10088
        assert page.is_svs
10089
        assert not page.is_jfif
10090
        assert page.is_subsampled
10091
        assert page.photometric == PHOTOMETRIC.RGB
10092
        assert page.is_tiled
10093
        assert page.compression == COMPRESSION.JPEG
10094
        assert page.shape == (32914, 46000, 3)
10095
        metadata = svs_description_metadata(page.description)
10096
        assert metadata['Header'].startswith('Aperio Image Library')
10097
        assert metadata['Originalheight'] == 33014
10098
        # page 4
10099
        page = tif.pages[4]
10100
        assert page.is_svs
10101
        assert page.is_reduced
10102
        assert page.photometric == PHOTOMETRIC.RGB
10103
        assert page.compression == COMPRESSION.LZW
10104
        assert page.shape == (463, 387, 3)
10105
        metadata = svs_description_metadata(page.description)
10106
        assert 'label 387x463' in metadata['Header']
10107
        assert_aszarr_method(page)
10108
        assert__str__(tif)
10109

10110

10111
@pytest.mark.skipif(
10112
    SKIP_PRIVATE or SKIP_CODECS or not imagecodecs.JPEG2K.available,
10113
    reason=REASON,
10114
)
10115
def test_read_svs_jp2k_33003_1():
10116
    """Test read Aperio SVS slide, JP2000 and LZW."""
10117
    fname = private_file('AperioSVS/JP2K-33003-1.svs')
10118
    with TiffFile(fname) as tif:
10119
        assert tif.is_svs
10120
        assert not tif.is_scanimage
10121
        assert len(tif.pages) == 6
10122
        assert len(tif.series) == 4
10123
        for page in tif.pages:
10124
            svs_description_metadata(page.description)
10125
        # first page
10126
        page = tif.pages.first
10127
        assert page.is_svs
10128
        assert not page.is_subsampled
10129
        assert page.photometric == PHOTOMETRIC.RGB
10130
        assert page.is_tiled
10131
        assert page.compression == COMPRESSION.APERIO_JP2000_YCBC
10132
        assert page.shape == (17497, 15374, 3)
10133
        metadata = svs_description_metadata(page.description)
10134
        assert metadata['Header'].startswith('Aperio Image Library')
10135
        assert metadata['Originalheight'] == 17597
10136
        # page 4
10137
        page = tif.pages[4]
10138
        assert page.is_svs
10139
        assert page.is_reduced
10140
        assert page.photometric == PHOTOMETRIC.RGB
10141
        assert page.compression == COMPRESSION.LZW
10142
        assert page.shape == (422, 415, 3)
10143
        metadata = svs_description_metadata(page.description)
10144
        assert 'label 415x422' in metadata['Header']
10145
        assert_aszarr_method(page)
10146
        assert__str__(tif)
10147

10148

10149
@pytest.mark.skipif(
10150
    SKIP_PRIVATE or SKIP_CODECS or not imagecodecs.JPEG.available,
10151
    reason=REASON,
10152
)
10153
def test_read_bif(caplog):
10154
    """Test read Ventana BIF slide."""
10155
    fname = private_file('VentanaBIF/OS-2.bif')
10156
    with TiffFile(fname) as tif:
10157
        assert tif.is_bif
10158
        assert len(tif.pages) == 12
10159
        assert len(tif.series) == 3
10160
        # first page
10161
        page = tif.pages.first
10162
        assert page.is_bif
10163
        assert page.photometric == PHOTOMETRIC.YCBCR
10164
        assert page.is_tiled
10165
        assert page.compression == COMPRESSION.JPEG
10166
        assert page.shape == (3008, 1008, 3)
10167

10168
        series = tif.series
10169
        assert 'not stiched' in caplog.text
10170
        # baseline
10171
        series = tif.series[0]
10172
        assert series.kind == 'bif'
10173
        assert series.name == 'Baseline'
10174
        assert len(series.levels) == 10
10175
        assert series.shape == (82960, 128000, 3)
10176
        assert series.dtype == numpy.uint8
10177
        # level 0
10178
        page = series.pages[0]
10179
        assert page.is_bif
10180
        assert page.is_tiled
10181
        assert page.photometric == PHOTOMETRIC.YCBCR
10182
        assert page.compression == COMPRESSION.JPEG
10183
        assert page.shape == (82960, 128000, 3)
10184
        assert page.description == 'level=0 mag=40 quality=90'
10185
        # level 5
10186
        page = series.levels[5].pages[0]
10187
        assert not page.is_bif
10188
        assert page.is_tiled
10189
        assert page.photometric == PHOTOMETRIC.YCBCR
10190
        assert page.compression == COMPRESSION.JPEG
10191
        assert page.shape == (2600, 4000, 3)
10192
        assert page.description == 'level=5 mag=1.25 quality=90'
10193

10194
        assert_aszarr_method(page)
10195
        assert__str__(tif)
10196

10197

10198
@pytest.mark.skipif(
10199
    SKIP_PRIVATE
10200
    or SKIP_LARGE
10201
    or SKIP_CODECS
10202
    or not imagecodecs.JPEG.available,
10203
    reason=REASON,
10204
)
10205
def test_read_scn_collection():
10206
    """Test read Leica SCN slide, JPEG."""
10207
    # collection of 43 CZYX images
10208
    # https://forum.image.sc/t/43585
10209
    fname = private_file(
10210
        'LeicaSCN/19-3-12_b5992c2e-5b6e-46f2-bf9b-d5872bdebdc1.SCN'
10211
    )
10212
    with TiffFile(fname) as tif:
10213
        assert tif.is_scn
10214
        assert tif.is_bigtiff
10215
        assert len(tif.pages) == 5358
10216
        assert len(tif.series) == 46
10217
        # first page
10218
        page = tif.pages.first
10219
        assert page.is_scn
10220
        assert page.is_tiled
10221
        assert page.photometric == PHOTOMETRIC.YCBCR
10222
        assert page.compression == COMPRESSION.JPEG
10223
        assert page.shape == (12990, 5741, 3)
10224
        metadata = tif.scn_metadata
10225
        assert metadata.startswith('<?xml version="1.0" encoding="utf-8"?>')
10226
        for series in tif.series[2:]:
10227
            assert series.kind == 'scn'
10228
            assert series.axes == 'CZYX'
10229
            assert series.shape[:2] == (4, 8)
10230
            assert len(series.levels) in {2, 3, 4, 5}
10231
            assert len(series.pages) == 32
10232
        # third series
10233
        series = tif.series[2]
10234
        assert series.shape == (4, 8, 946, 993)
10235
        assert_aszarr_method(series)
10236
        assert__str__(tif)
10237

10238

10239
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
10240
def test_read_scanimage_metadata():
10241
    """Test read ScanImage metadata."""
10242
    fname = private_file('ScanImage/TS_UnitTestImage_BigTIFF.tif')
10243
    with open(fname, 'rb') as fh:
10244
        frame_data, roi_data, version = read_scanimage_metadata(fh)
10245
    assert version == 3
10246
    assert frame_data['SI.hChannels.channelType'] == ['stripe', 'stripe']
10247
    assert roi_data['RoiGroups']['imagingRoiGroup']['ver'] == 1
10248

10249

10250
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
10251
def test_read_scanimage_2021():
10252
    """Test read ScanImage metadata."""
10253
    # https://github.com/cgohlke/tifffile/issues/46
10254
    fname = private_file('ScanImage/ScanImage2021_3frames.tif')
10255
    with open(fname, 'rb') as fh:
10256
        frame_data, roi_data, version = read_scanimage_metadata(fh)
10257
    assert frame_data['SI.hChannels.channelType'] == [
10258
        'stripe',
10259
        'stripe',
10260
        'stripe',
10261
        'stripe',
10262
    ]
10263
    assert version == 4
10264
    assert roi_data['RoiGroups']['imagingRoiGroup']['ver'] == 1
10265

10266
    with TiffFile(fname) as tif:
10267
        assert tif.is_scanimage
10268
        assert len(tif.pages) == 3
10269
        assert len(tif.series) == 1
10270
        assert tif.series[0].shape == (3, 256, 256)
10271
        assert tif.series[0].axes == 'TYX'
10272
        # non-varying scanimage_metadata
10273
        assert tif.scanimage_metadata['version'] == 4
10274
        assert 'FrameData' in tif.scanimage_metadata
10275
        assert 'RoiGroups' in tif.scanimage_metadata
10276
        # assert page properties
10277
        page = tif.pages.first
10278
        assert page.is_scanimage
10279
        assert page.is_contiguous
10280
        assert page.compression == COMPRESSION.NONE
10281
        assert page.imagewidth == 256
10282
        assert page.imagelength == 256
10283
        assert page.bitspersample == 16
10284
        assert page.samplesperpixel == 1
10285
        # description tags
10286
        metadata = scanimage_description_metadata(page.description)
10287
        assert metadata['epoch'] == [2021, 3, 1, 17, 31, 28.047]
10288
        assert_aszarr_method(tif)
10289
        assert__str__(tif)
10290

10291

10292
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
10293
def test_read_scanimage_no_framedata():
10294
    """Test read ScanImage no FrameData."""
10295
    fname = private_file('ScanImage/PSF001_ScanImage36.tif')
10296
    with TiffFile(fname) as tif:
10297
        assert tif.is_scanimage
10298
        assert len(tif.pages) == 100
10299
        assert len(tif.series) == 1
10300
        # no non-tiff scanimage_metadata
10301
        assert not tif.scanimage_metadata
10302
        # assert page properties
10303
        page = tif.pages.first
10304
        assert page.is_scanimage
10305
        assert page.is_contiguous
10306
        assert page.compression == COMPRESSION.NONE
10307
        assert page.imagewidth == 256
10308
        assert page.imagelength == 256
10309
        assert page.bitspersample == 16
10310
        assert page.samplesperpixel == 1
10311
        # description tags
10312
        metadata = scanimage_description_metadata(page.description)
10313
        assert metadata['state.software.version'] == 3.6
10314
        assert_aszarr_method(tif)
10315
        assert__str__(tif)
10316

10317

10318
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_LARGE, reason=REASON)
10319
def test_read_scanimage_2gb():
10320
    """Test read ScanImage non-BigTIFF > 2 GB.
10321

10322
    https://github.com/MouseLand/suite2p/issues/149
10323

10324
    """
10325
    fname = private_file('ScanImage/M161209TH_01__001.tif')
10326
    with TiffFile(fname) as tif:
10327
        assert tif.is_scanimage
10328
        assert len(tif.pages) == 5980
10329
        assert len(tif.series) == 1
10330
        assert tif.series[0].kind == 'scanimage'
10331
        # no non-tiff scanimage_metadata
10332
        assert 'version' not in tif.scanimage_metadata
10333
        assert 'FrameData' not in tif.scanimage_metadata
10334
        assert 'RoiGroups' not in tif.scanimage_metadata
10335
        # assert page properties
10336
        page = tif.pages.first
10337
        assert isinstance(page, TiffPage)
10338
        assert not page.is_frame
10339
        assert not page.is_virtual
10340
        assert not page.is_subifd
10341
        assert page.is_scanimage
10342
        assert page.is_contiguous
10343
        assert page.compression == COMPRESSION.NONE
10344
        assert page.imagewidth == 512
10345
        assert page.imagelength == 512
10346
        assert page.bitspersample == 16
10347
        assert page.samplesperpixel == 1
10348
        # using virtual frames
10349
        frame = tif.pages[-1]
10350
        assert isinstance(frame, TiffFrame)
10351
        assert frame.is_frame
10352
        assert frame.is_virtual
10353
        assert not frame.is_subifd
10354
        assert frame.offset <= 0
10355
        assert frame.index == 5979
10356
        assert frame.dataoffsets[0] == 3163182856
10357
        assert frame.databytecounts[0] == 8192  # 524288
10358
        assert len(frame.dataoffsets) == 64
10359
        assert len(frame.databytecounts) == 64
10360
        # description tags
10361
        metadata = scanimage_description_metadata(page.description)
10362
        assert metadata['scanimage.SI5.VERSION_MAJOR'] == 5
10363
        # assert data
10364
        data = tif.asarray()
10365
        assert data[5979, 256, 256] == 71
10366
        data = frame.asarray()
10367
        assert data[256, 256] == 71
10368
        assert_aszarr_method(tif)
10369
        assert__str__(tif)
10370

10371

10372
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
10373
def test_read_scanimage_bigtiff():
10374
    """Test read ScanImage BigTIFF."""
10375
    # https://github.com/cgohlke/tifffile/issues/29
10376
    fname = private_file('ScanImage/area1__00001.tif')
10377
    with TiffFile(fname) as tif:
10378
        assert tif.is_scanimage
10379
        assert len(tif.pages) == 162
10380
        assert len(tif.series) == 1
10381
        assert tif.series[0].kind == 'scanimage'
10382
        # assert page properties
10383
        page = tif.pages.first
10384
        assert page.is_scanimage
10385
        assert page.is_contiguous
10386
        assert page.compression == COMPRESSION.NONE
10387
        assert page.imagewidth == 512
10388
        assert page.imagelength == 512
10389
        assert page.bitspersample == 16
10390
        assert page.samplesperpixel == 1
10391
        # metadata in description, software, artist tags
10392
        metadata = scanimage_description_metadata(page.description)
10393
        assert metadata['frameNumbers'] == 1
10394
        metadata = scanimage_description_metadata(page.tags['Software'].value)
10395
        assert metadata['SI.TIFF_FORMAT_VERSION'] == 3
10396
        metadata = scanimage_artist_metadata(page.tags['Artist'].value)
10397
        assert metadata['RoiGroups']['imagingRoiGroup']['ver'] == 1
10398
        metadata = tif.scanimage_metadata
10399
        assert metadata['version'] == 3
10400
        assert metadata['FrameData']['SI.TIFF_FORMAT_VERSION'] == 3
10401
        assert metadata['RoiGroups']['imagingRoiGroup']['ver'] == 1
10402
        assert 'Description' not in metadata
10403
        # assert page offsets are correct
10404
        assert tif.pages[-1].offset == 84527590  # not 84526526 (calculated)
10405
        # read image data
10406
        assert_aszarr_method(tif)
10407
        assert__str__(tif)
10408

10409

10410
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
10411
def test_read_ome_single_channel():
10412
    """Test read OME image."""
10413
    # 2D (single image)
10414
    # OME-TIFF reference images from
10415
    # https://www.openmicroscopy.org/site/support/ome-model/ome-tiff
10416
    fname = public_file('OME/bioformats-artificial/single-channel.ome.tif')
10417
    with TiffFile(fname) as tif:
10418
        assert tif.is_ome
10419
        assert tif.byteorder == '>'
10420
        assert len(tif.pages) == 1
10421
        assert len(tif.series) == 1
10422
        # assert page properties
10423
        page = tif.pages.first
10424
        assert page.is_contiguous
10425
        assert page.tags['Software'].value[:15] == 'OME Bio-Formats'
10426
        assert page.compression == COMPRESSION.NONE
10427
        assert page.imagewidth == 439
10428
        assert page.imagelength == 167
10429
        assert page.bitspersample == 8
10430
        assert page.samplesperpixel == 1
10431
        # assert series properties
10432
        series = tif.series[0]
10433
        assert not series.is_multifile
10434
        assert series.dtype == numpy.int8
10435
        assert series.shape == (167, 439)
10436
        assert series.axes == 'YX'
10437
        assert series.kind == 'ome'
10438
        assert series.get_shape(False) == (1, 1, 1, 167, 439, 1)
10439
        assert series.get_axes(False) == 'TCZYXS'
10440
        # assert data
10441
        data = tif.asarray()
10442
        assert isinstance(data, numpy.ndarray)
10443
        assert data.shape == (167, 439)
10444
        assert data.dtype == numpy.int8
10445
        assert data[158, 428] == 91
10446
        assert_aszarr_method(tif, data)
10447
        assert__str__(tif)
10448

10449

10450
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
10451
def test_read_ome_multi_channel():
10452
    """Test read OME multi channel image."""
10453
    # 2D (3 channels)
10454
    fname = public_file('OME/bioformats-artificial/multi-channel.ome.tiff')
10455
    with TiffFile(fname) as tif:
10456
        assert tif.is_ome
10457
        assert tif.byteorder == '>'
10458
        assert len(tif.pages) == 3
10459
        assert len(tif.series) == 1
10460
        # assert page properties
10461
        page = tif.pages.first
10462
        assert page.is_contiguous
10463
        assert page.tags['Software'].value[:15] == 'OME Bio-Formats'
10464
        assert page.compression == COMPRESSION.NONE
10465
        assert page.imagewidth == 439
10466
        assert page.imagelength == 167
10467
        assert page.bitspersample == 8
10468
        assert page.samplesperpixel == 1
10469
        # assert series properties
10470
        series = tif.series[0]
10471
        assert series.shape == (3, 167, 439)
10472
        assert series.dtype == numpy.int8
10473
        assert series.axes == 'CYX'
10474
        assert series.kind == 'ome'
10475
        assert series.get_shape(False) == (1, 3, 1, 167, 439, 1)
10476
        assert series.get_axes(False) == 'TCZYXS'
10477
        assert not series.is_multifile
10478
        # assert data
10479
        data = tif.asarray()
10480
        assert isinstance(data, numpy.ndarray)
10481
        assert data.shape == (3, 167, 439)
10482
        assert data.dtype == numpy.int8
10483
        assert data[2, 158, 428] == 91
10484
        assert_aszarr_method(tif, data)
10485
        # don't squeeze
10486
        data = tif.asarray(squeeze=False)
10487
        assert_aszarr_method(tif, data, squeeze=False)
10488
        assert__str__(tif)
10489

10490

10491
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
10492
def test_read_ome_z_series():
10493
    """Test read OME volume."""
10494
    # 3D (5 focal planes)
10495
    fname = public_file('OME/bioformats-artificial/z-series.ome.tif')
10496
    with TiffFile(fname) as tif:
10497
        assert tif.is_ome
10498
        assert tif.byteorder == '>'
10499
        assert len(tif.pages) == 5
10500
        assert len(tif.series) == 1
10501
        # assert page properties
10502
        page = tif.pages.first
10503
        assert page.is_contiguous
10504
        assert page.tags['Software'].value[:15] == 'OME Bio-Formats'
10505
        assert page.compression == COMPRESSION.NONE
10506
        assert page.imagewidth == 439
10507
        assert page.imagelength == 167
10508
        assert page.bitspersample == 8
10509
        assert page.samplesperpixel == 1
10510
        # assert series properties
10511
        series = tif.series[0]
10512
        assert series.shape == (5, 167, 439)
10513
        assert series.dtype == numpy.int8
10514
        assert series.axes == 'ZYX'
10515
        assert series.kind == 'ome'
10516
        assert series.get_shape(False) == (1, 1, 5, 167, 439, 1)
10517
        assert series.get_axes(False) == 'TCZYXS'
10518
        assert not series.is_multifile
10519
        # assert data
10520
        data = tif.asarray()
10521
        assert isinstance(data, numpy.ndarray)
10522
        assert data.shape == (5, 167, 439)
10523
        assert data.dtype == numpy.int8
10524
        assert data[4, 158, 428] == 91
10525
        assert_aszarr_method(tif, data)
10526
        assert__str__(tif)
10527

10528

10529
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
10530
def test_read_ome_multi_channel_z_series():
10531
    """Test read OME multi-channel volume."""
10532
    # 3D (5 focal planes, 3 channels)
10533
    fname = public_file(
10534
        'OME/bioformats-artificial/multi-channel-z-series.ome.tiff'
10535
    )
10536
    with TiffFile(fname) as tif:
10537
        assert tif.is_ome
10538
        assert tif.byteorder == '>'
10539
        assert len(tif.pages) == 15
10540
        assert len(tif.series) == 1
10541
        # assert page properties
10542
        page = tif.pages.first
10543
        assert page.is_contiguous
10544
        assert page.tags['Software'].value[:15] == 'OME Bio-Formats'
10545
        assert page.compression == COMPRESSION.NONE
10546
        assert page.imagewidth == 439
10547
        assert page.imagelength == 167
10548
        assert page.bitspersample == 8
10549
        assert page.samplesperpixel == 1
10550
        # assert series properties
10551
        series = tif.series[0]
10552
        assert series.shape == (3, 5, 167, 439)
10553
        assert series.dtype == numpy.int8
10554
        assert series.axes == 'CZYX'
10555
        assert series.kind == 'ome'
10556
        assert series.get_shape(False) == (1, 3, 5, 167, 439, 1)
10557
        assert series.get_axes(False) == 'TCZYXS'
10558
        assert not series.is_multifile
10559
        # assert data
10560
        data = tif.asarray()
10561
        assert isinstance(data, numpy.ndarray)
10562
        assert data.shape == (3, 5, 167, 439)
10563
        assert data.dtype == numpy.int8
10564
        assert data[2, 4, 158, 428] == 91
10565
        assert_aszarr_method(tif, data)
10566
        assert__str__(tif)
10567

10568

10569
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
10570
def test_read_ome_time_series():
10571
    """Test read OME time-series of images."""
10572
    # 3D (7 time points)
10573
    fname = public_file('OME/bioformats-artificial/time-series.ome.tiff')
10574
    with TiffFile(fname) as tif:
10575
        assert tif.is_ome
10576
        assert tif.byteorder == '>'
10577
        assert len(tif.pages) == 7
10578
        assert len(tif.series) == 1
10579
        # assert page properties
10580
        page = tif.pages.first
10581
        assert page.is_contiguous
10582
        assert page.tags['Software'].value[:15] == 'OME Bio-Formats'
10583
        assert page.compression == COMPRESSION.NONE
10584
        assert page.imagewidth == 439
10585
        assert page.imagelength == 167
10586
        assert page.bitspersample == 8
10587
        assert page.samplesperpixel == 1
10588
        # assert series properties
10589
        series = tif.series[0]
10590
        assert series.shape == (7, 167, 439)
10591
        assert series.dtype == numpy.int8
10592
        assert series.axes == 'TYX'
10593
        assert series.kind == 'ome'
10594
        assert series.get_shape(False) == (7, 1, 1, 167, 439, 1)
10595
        assert series.get_axes(False) == 'TCZYXS'
10596
        assert not series.is_multifile
10597
        # assert data
10598
        data = tif.asarray()
10599
        assert isinstance(data, numpy.ndarray)
10600
        assert data.shape == (7, 167, 439)
10601
        assert data.dtype == numpy.int8
10602
        assert data[6, 158, 428] == 91
10603
        assert_aszarr_method(tif, data)
10604
        assert__str__(tif)
10605

10606

10607
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
10608
def test_read_ome_multi_channel_time_series():
10609
    """Test read OME time-series of multi-channel images."""
10610
    # 3D (7 time points, 3 channels)
10611
    fname = public_file(
10612
        'OME/bioformats-artificial/multi-channel-time-series.ome.tiff'
10613
    )
10614
    with TiffFile(fname) as tif:
10615
        assert tif.is_ome
10616
        assert tif.byteorder == '>'
10617
        assert len(tif.pages) == 21
10618
        assert len(tif.series) == 1
10619
        # assert page properties
10620
        page = tif.pages.first
10621
        assert page.is_contiguous
10622
        assert page.tags['Software'].value[:15] == 'OME Bio-Formats'
10623
        assert page.compression == COMPRESSION.NONE
10624
        assert page.imagewidth == 439
10625
        assert page.imagelength == 167
10626
        assert page.bitspersample == 8
10627
        assert page.samplesperpixel == 1
10628
        # assert series properties
10629
        series = tif.series[0]
10630
        assert series.shape == (7, 3, 167, 439)
10631
        assert series.dtype == numpy.int8
10632
        assert series.axes == 'TCYX'
10633
        assert series.kind == 'ome'
10634
        assert series.get_shape(False) == (7, 3, 1, 167, 439, 1)
10635
        assert series.get_axes(False) == 'TCZYXS'
10636
        assert not series.is_multifile
10637
        # assert data
10638
        data = tif.asarray()
10639
        assert isinstance(data, numpy.ndarray)
10640
        assert data.shape == (7, 3, 167, 439)
10641
        assert data.dtype == numpy.int8
10642
        assert data[6, 2, 158, 428] == 91
10643
        assert_aszarr_method(tif, data)
10644
        # don't squeeze
10645
        data = tif.asarray(squeeze=False)
10646
        assert_aszarr_method(tif, data, squeeze=False)
10647
        assert__str__(tif)
10648

10649

10650
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
10651
def test_read_ome_4d_series():
10652
    """Test read OME time-series of volumes."""
10653
    # 4D (7 time points, 5 focal planes)
10654
    fname = public_file('OME/bioformats-artificial/4D-series.ome.tiff')
10655
    with TiffFile(fname) as tif:
10656
        assert tif.is_ome
10657
        assert tif.byteorder == '>'
10658
        assert len(tif.pages) == 35
10659
        assert len(tif.series) == 1
10660
        # assert page properties
10661
        page = tif.pages.first
10662
        assert page.is_contiguous
10663
        assert page.tags['Software'].value[:15] == 'OME Bio-Formats'
10664
        assert page.compression == COMPRESSION.NONE
10665
        assert page.imagewidth == 439
10666
        assert page.imagelength == 167
10667
        assert page.bitspersample == 8
10668
        assert page.samplesperpixel == 1
10669
        # assert series properties
10670
        series = tif.series[0]
10671
        assert series.shape == (7, 5, 167, 439)
10672
        assert series.dtype == numpy.int8
10673
        assert series.axes == 'TZYX'
10674
        assert series.kind == 'ome'
10675
        assert not series.is_multifile
10676
        # assert data
10677
        data = tif.asarray()
10678
        assert isinstance(data, numpy.ndarray)
10679
        assert data.shape == (7, 5, 167, 439)
10680
        assert data.dtype == numpy.int8
10681
        assert data[6, 4, 158, 428] == 91
10682
        assert_aszarr_method(tif, data)
10683
        assert__str__(tif)
10684

10685

10686
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
10687
def test_read_ome_multi_channel_4d_series():
10688
    """Test read OME time-series of multi-channel volumes."""
10689
    # 4D (7 time points, 5 focal planes, 3 channels)
10690
    fname = public_file(
10691
        'OME/bioformats-artificial/multi-channel-4D-series.ome.tiff'
10692
    )
10693
    with TiffFile(fname) as tif:
10694
        assert tif.is_ome
10695
        assert tif.byteorder == '>'
10696
        assert len(tif.pages) == 105
10697
        assert len(tif.series) == 1
10698
        # assert page properties
10699
        page = tif.pages.first
10700
        assert page.is_contiguous
10701
        assert page.tags['Software'].value[:15] == 'OME Bio-Formats'
10702
        assert page.compression == COMPRESSION.NONE
10703
        assert page.imagewidth == 439
10704
        assert page.imagelength == 167
10705
        assert page.bitspersample == 8
10706
        assert page.samplesperpixel == 1
10707
        # assert series properties
10708
        series = tif.series[0]
10709
        assert series.shape == (7, 3, 5, 167, 439)
10710
        assert series.dtype == numpy.int8
10711
        assert series.axes == 'TCZYX'
10712
        assert series.kind == 'ome'
10713
        assert series.get_shape(False) == (7, 3, 5, 167, 439, 1)
10714
        assert series.get_axes(False) == 'TCZYXS'
10715
        assert not series.is_multifile
10716
        # assert data
10717
        data = tif.asarray()
10718
        assert isinstance(data, numpy.ndarray)
10719
        assert data.shape == (7, 3, 5, 167, 439)
10720
        assert data.dtype == numpy.int8
10721
        assert data[6, 0, 4, 158, 428] == 91
10722
        assert_aszarr_method(tif, data)
10723
        # don't squeeze
10724
        data = tif.asarray(squeeze=False)
10725
        assert_aszarr_method(tif, data, squeeze=False)
10726
        assert__str__(tif)
10727

10728

10729
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
10730
def test_read_ome_modulo_flim():
10731
    """Test read OME modulo FLIM."""
10732
    fname = public_file('OME/modulo/FLIM-ModuloAlongC.ome.tiff')
10733
    with TiffFile(fname) as tif:
10734
        assert tif.is_ome
10735
        assert tif.byteorder == '>'
10736
        assert len(tif.pages) == 16
10737
        assert len(tif.series) == 1
10738
        # assert page properties
10739
        page = tif.pages.first
10740
        assert page.is_contiguous
10741
        assert page.tags['Software'].value[:15] == 'OME Bio-Formats'
10742
        assert page.compression == COMPRESSION.NONE
10743
        assert page.imagewidth == 180
10744
        assert page.imagelength == 150
10745
        assert page.bitspersample == 8
10746
        assert page.samplesperpixel == 1
10747
        # assert series properties
10748
        series = tif.series[0]
10749
        assert series.shape == (2, 8, 150, 180)
10750
        assert series.dtype == numpy.int8
10751
        assert series.axes == 'CHYX'
10752
        assert series.kind == 'ome'
10753
        assert series.get_shape(False) == (1, 2, 8, 1, 150, 180, 1)
10754
        assert series.get_axes(False) == 'TCHZYXS'
10755
        assert not series.is_multifile
10756
        # assert data
10757
        data = tif.asarray()
10758
        assert isinstance(data, numpy.ndarray)
10759
        assert data.shape == (2, 8, 150, 180)
10760
        assert data.dtype == numpy.int8
10761
        assert data[1, 7, 143, 172] == 92
10762
        assert_aszarr_method(tif, data)
10763
        # don't squeeze
10764
        data = tif.asarray(squeeze=False)
10765
        assert_aszarr_method(tif, data, squeeze=False)
10766
        assert__str__(tif)
10767

10768

10769
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
10770
def test_read_ome_modulo_flim_tcspc():
10771
    """Test read OME modulo FLIM TSCPC."""
10772
    # Two channels each recorded at two timepoints and eight histogram bins
10773
    fname = public_file('OME/modulo/FLIM-ModuloAlongT-TSCPC.ome.tiff')
10774
    with TiffFile(fname) as tif:
10775
        assert tif.is_ome
10776
        assert tif.byteorder == '<'
10777
        assert len(tif.pages) == 32
10778
        assert len(tif.series) == 1
10779
        # assert page properties
10780
        page = tif.pages.first
10781
        assert page.is_contiguous
10782
        assert page.tags['Software'].value[:15] == 'OME Bio-Formats'
10783
        assert page.compression == COMPRESSION.NONE
10784
        assert page.imagewidth == 180
10785
        assert page.imagelength == 200
10786
        assert page.bitspersample == 8
10787
        assert page.samplesperpixel == 1
10788
        # assert series properties
10789
        series = tif.series[0]
10790
        assert series.shape == (2, 8, 2, 200, 180)
10791
        assert series.dtype == numpy.int8
10792
        assert series.axes == 'THCYX'
10793
        assert series.kind == 'ome'
10794
        assert not series.is_multifile
10795
        # assert data
10796
        data = tif.asarray()
10797
        assert isinstance(data, numpy.ndarray)
10798
        assert data.shape == (2, 8, 2, 200, 180)
10799
        assert data.dtype == numpy.int8
10800
        assert data[1, 7, 1, 190, 161] == 92
10801
        assert_aszarr_method(tif, data)
10802
        assert__str__(tif)
10803

10804

10805
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
10806
def test_read_ome_modulo_spim():
10807
    """Test read OME modulo SPIM."""
10808
    # 2x2 tile of planes each recorded at 4 angles
10809
    fname = public_file('OME/modulo/SPIM-ModuloAlongZ.ome.tiff')
10810
    with TiffFile(fname) as tif:
10811
        assert tif.is_ome
10812
        assert tif.byteorder == '<'
10813
        assert len(tif.pages) == 192
10814
        assert len(tif.series) == 1
10815
        # assert page properties
10816
        page = tif.pages.first
10817
        assert page.is_contiguous
10818
        assert page.tags['Software'].value == 'OME Bio-Formats 5.2.0-SNAPSHOT'
10819
        assert page.compression == COMPRESSION.NONE
10820
        assert page.imagewidth == 160
10821
        assert page.imagelength == 220
10822
        assert page.bitspersample == 8
10823
        assert page.samplesperpixel == 1
10824
        # assert series properties
10825
        series = tif.series[0]
10826
        assert series.shape == (3, 4, 2, 4, 2, 220, 160)
10827
        assert series.dtype == numpy.uint8
10828
        assert series.axes == 'TRZACYX'
10829
        assert series.kind == 'ome'
10830
        assert not series.is_multifile
10831
        # assert data
10832
        data = tif.asarray()
10833
        assert isinstance(data, numpy.ndarray)
10834
        assert data.shape == (3, 4, 2, 4, 2, 220, 160)
10835
        assert data.dtype == numpy.uint8
10836
        assert data[2, 3, 1, 3, 1, 210, 151] == 92
10837
        assert_aszarr_method(tif, data)
10838
        assert__str__(tif)
10839

10840

10841
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
10842
def test_read_ome_modulo_lambda():
10843
    """Test read OME modulo LAMBDA."""
10844
    # Excitation of 5 wavelength [big-lambda] each recorded at 10 emission
10845
    # wavelength ranges [lambda].
10846
    fname = public_file('OME/modulo/LAMBDA-ModuloAlongZ-ModuloAlongT.ome.tiff')
10847
    with TiffFile(fname) as tif:
10848
        assert tif.is_ome
10849
        assert tif.byteorder == '<'
10850
        assert len(tif.pages) == 50
10851
        assert len(tif.series) == 1
10852
        # assert page properties
10853
        page = tif.pages.first
10854
        assert page.is_contiguous
10855
        assert page.tags['Software'].value == 'OME Bio-Formats 5.2.0-SNAPSHOT'
10856
        assert page.compression == COMPRESSION.NONE
10857
        assert page.imagewidth == 200
10858
        assert page.imagelength == 200
10859
        assert page.bitspersample == 8
10860
        assert page.samplesperpixel == 1
10861
        # assert series properties
10862
        series = tif.series[0]
10863
        assert series.shape == (10, 5, 200, 200)
10864
        assert series.dtype == numpy.uint8
10865
        assert series.axes == 'EPYX'
10866
        assert series.kind == 'ome'
10867
        assert not series.is_multifile
10868
        # assert data
10869
        data = tif.asarray()
10870
        assert isinstance(data, numpy.ndarray)
10871
        assert data.shape == (10, 5, 200, 200)
10872
        assert data.dtype == numpy.uint8
10873
        assert data[9, 4, 190, 192] == 92
10874
        assert_aszarr_method(tif, data)
10875
        assert__str__(tif)
10876

10877

10878
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
10879
def test_read_ome_multiimage_pixels():
10880
    """Test read OME with three image series."""
10881
    fname = public_file('OME/bioformats-artificial/multi-image-pixels.ome.tif')
10882
    with TiffFile(fname) as tif:
10883
        assert tif.is_ome
10884
        assert tif.byteorder == '>'
10885
        assert len(tif.pages) == 86
10886
        assert len(tif.series) == 3
10887
        # assert page properties
10888
        for i, axes, shape in (
10889
            (0, 'CTYX', (2, 7, 555, 431)),
10890
            (1, 'TZYX', (6, 2, 461, 348)),
10891
            (2, 'TZCYX', (4, 5, 3, 239, 517)),
10892
        ):
10893
            series = tif.series[i]
10894
            assert series.kind == 'ome'
10895
            page = series.pages[0]
10896
            assert page.is_contiguous
10897
            assert page.tags['Software'].value == 'LOCI Bio-Formats'
10898
            assert page.compression == COMPRESSION.NONE
10899
            assert page.imagewidth == shape[-1]
10900
            assert page.imagelength == shape[-2]
10901
            assert page.bitspersample == 8
10902
            assert page.samplesperpixel == 1
10903
            # assert series properties
10904
            assert series.shape == shape
10905
            assert series.dtype == numpy.uint8
10906
            assert series.axes == axes
10907
            assert not series.is_multifile
10908
            # assert data
10909
            data = tif.asarray(series=i)
10910
            assert isinstance(data, numpy.ndarray)
10911
            assert data.shape == shape
10912
            assert data.dtype == numpy.uint8
10913
            assert_aszarr_method(series, data)
10914
            assert__str__(tif)
10915

10916

10917
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
10918
def test_read_ome_multiimage_nouuid():
10919
    """Test read single-file, multi-image OME without UUID."""
10920
    fname = private_file(
10921
        'OMETIFF.jl/singles/181003_multi_pos_time_course_1_MMStack.ome.tif'
10922
    )
10923
    with TiffFile(fname, is_mmstack=False) as tif:
10924
        assert tif.is_ome
10925
        assert tif.byteorder == '<'
10926
        assert len(tif.pages) == 20
10927
        assert len(tif.series) == 2
10928
        # assert page properties
10929
        for i in (0, 1):
10930
            series = tif.series[i]
10931
            page = series.pages[0]
10932
            assert page.is_imagej == (i == 0)
10933
            assert page.is_ome == (i == 0)
10934
            assert page.is_micromanager
10935
            assert page.is_contiguous
10936
            assert page.compression == COMPRESSION.NONE
10937
            assert page.imagewidth == 256
10938
            assert page.imagelength == 256
10939
            assert page.bitspersample == 16
10940
            assert page.samplesperpixel == 1
10941
            # assert series properties
10942
            assert series.shape == (10, 256, 256)
10943
            assert series.dtype == numpy.uint16
10944
            assert series.axes == 'TYX'
10945
            assert series.kind == 'ome'
10946
            assert not series.is_multifile
10947
            # assert data
10948
            data = tif.asarray(series=i)
10949
            assert_array_equal(
10950
                data, imread(fname, series=i, is_micromanager=False)
10951
            )
10952
            assert isinstance(data, numpy.ndarray)
10953
            assert data.shape == (10, 256, 256)
10954
            assert data.dtype == numpy.uint16
10955
            assert data[5, 128, 128] == (18661, 16235)[i]
10956
            assert_aszarr_method(series, data)
10957
            assert__str__(tif)
10958

10959

10960
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
10961
def test_read_ome_zen_2chzt():
10962
    """Test read OME time-series of two-channel volumes by ZEN 2011."""
10963
    fname = private_file('OME/zen_2chzt.ome.tiff')
10964
    with TiffFile(fname) as tif:
10965
        assert tif.is_ome
10966
        assert tif.byteorder == '<'
10967
        assert len(tif.pages) == 798
10968
        assert len(tif.series) == 1
10969
        # assert page properties
10970
        page = tif.pages.first
10971
        assert page.is_contiguous
10972
        assert page.tags['Software'].value == 'ZEN 2011 (blue edition)'
10973
        assert page.compression == COMPRESSION.NONE
10974
        assert page.imagewidth == 400
10975
        assert page.imagelength == 300
10976
        assert page.bitspersample == 8
10977
        assert page.samplesperpixel == 1
10978
        # assert series properties
10979
        series = tif.series[0]
10980
        assert series.shape == (2, 19, 21, 300, 400)
10981
        assert series.dtype == numpy.uint8
10982
        assert series.axes == 'CTZYX'
10983
        assert series.kind == 'ome'
10984
        assert not series.is_multifile
10985
        # assert data
10986
        data = tif.asarray()
10987
        assert isinstance(data, numpy.ndarray)
10988
        assert data.shape == (2, 19, 21, 300, 400)
10989
        assert data.dtype == numpy.uint8
10990
        assert data[1, 10, 10, 100, 245] == 78
10991
        assert_aszarr_method(tif, data)
10992
        assert__str__(tif, 0)
10993

10994

10995
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_LARGE, reason=REASON)
10996
def test_read_ome_multifile():
10997
    """Test read OME CTZYX series in 86 files."""
10998
    # (2, 43, 10, 512, 512) CTZYX uint8 in 86 files, 10 pages each
10999
    fname = public_file('OME/tubhiswt-4D/tubhiswt_C0_TP10.ome.tif')
11000
    with TiffFile(fname) as tif:
11001
        assert tif.is_ome
11002
        assert tif.byteorder == '<'
11003
        assert len(tif.pages) == 10
11004
        assert len(tif.series) == 1
11005
        # assert page properties
11006
        page = tif.pages.first
11007
        assert page.is_contiguous
11008
        assert page.tags['Software'].value[:15] == 'OME Bio-Formats'
11009
        assert page.compression == COMPRESSION.NONE
11010
        assert page.imagewidth == 512
11011
        assert page.imagelength == 512
11012
        assert page.bitspersample == 8
11013
        assert page.samplesperpixel == 1
11014
        # assert series properties
11015
        series = tif.series[0]
11016
        assert series.shape == (2, 43, 10, 512, 512)
11017
        assert series.dtype == numpy.uint8
11018
        assert series.axes == 'CTZYX'
11019
        assert series.kind == 'ome'
11020
        assert series.is_multifile
11021
        # assert other files are closed after TiffFile._series_ome
11022
        for page in tif.series[0].pages:
11023
            assert bool(page.parent.filehandle._fh) == (page.parent == tif)
11024
        # assert data
11025
        data = tif.asarray(out='memmap')
11026
        assert isinstance(data, numpy.memmap)
11027
        assert data.shape == (2, 43, 10, 512, 512)
11028
        assert data.dtype == numpy.uint8
11029
        assert data[1, 42, 9, 426, 272] == 123
11030
        # assert other files are still closed after TiffFile.asarray
11031
        for page in tif.series[0].pages:
11032
            assert bool(page.parent.filehandle._fh) == (page.parent == tif)
11033
        assert tif.filehandle._fh
11034
        assert__str__(tif)
11035
        # test aszarr
11036
        assert_aszarr_method(tif, data)
11037
        assert_aszarr_method(tif, data, chunkmode='page')
11038
        del data
11039
        # assert other files are still closed after ZarrStore.close
11040
        for page in tif.series[0].pages:
11041
            assert bool(page.parent.filehandle._fh) == (page.parent == tif)
11042

11043
    # assert all files stay open
11044
    # with TiffFile(fname) as tif:
11045
    #     for page in tif.series[0].pages:
11046
    #         self.assertTrue(page.parent.filehandle._fh)
11047
    #     data = tif.asarray(out='memmap')
11048
    #     for page in tif.series[0].pages:
11049
    #         self.assertTrue(page.parent.filehandle._fh)
11050

11051

11052
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_LARGE, reason=REASON)
11053
def test_read_ome_multifile_missing(caplog):
11054
    """Test read OME referencing missing files."""
11055
    # (2, 43, 10, 512, 512) CTZYX uint8, 85 files missing
11056
    fname = private_file('OME/tubhiswt_C0_TP34.ome.tif')
11057
    with TiffFile(fname) as tif:
11058
        assert tif.is_ome
11059
        assert tif.byteorder == '<'
11060
        assert len(tif.pages) == 10
11061
        assert len(tif.series) == 1
11062
        assert 'failed to read' in caplog.text
11063
        # assert page properties
11064
        page = tif.pages.first
11065
        TiffPage._str(page, 4)
11066
        assert page.is_contiguous
11067
        assert page.tags['Software'].value[:15] == 'OME Bio-Formats'
11068
        assert page.compression == COMPRESSION.NONE
11069
        assert page.imagewidth == 512
11070
        assert page.imagelength == 512
11071
        assert page.bitspersample == 8
11072
        assert page.samplesperpixel == 1
11073
        page = tif.pages[-1]
11074
        TiffPage._str(page, 4)
11075
        assert page.shape == (512, 512)
11076
        # assert series properties
11077
        series = tif.series[0]
11078
        assert series.shape == (2, 43, 10, 512, 512)
11079
        assert series.dtype == numpy.uint8
11080
        assert series.axes == 'CTZYX'
11081
        assert series.kind == 'ome'
11082
        assert series.is_multifile
11083
        # assert data
11084
        data = tif.asarray(out='memmap')
11085
        assert isinstance(data, numpy.memmap)
11086
        assert data.shape == (2, 43, 10, 512, 512)
11087
        assert data.dtype == numpy.uint8
11088
        assert data[0, 34, 4, 303, 206] == 82
11089
        assert data[1, 25, 2, 425, 272] == 196
11090
        assert_aszarr_method(tif, data)
11091
        assert_aszarr_method(tif, data, chunkmode='page')
11092
        del data
11093
        assert__str__(tif)
11094

11095

11096
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_LARGE, reason=REASON)
11097
def test_read_ome_multifile_binaryio(caplog):
11098
    """Test read OME multifile series with BinaryIO."""
11099
    # (2, 43, 10, 512, 512) CTZYX uint8, 85 files missing
11100
    fname = private_file('OME/tubhiswt_C0_TP34.ome.tif')
11101
    with open(fname, 'rb') as fh:
11102
        bytesio = BytesIO(fh.read())
11103
    with TiffFile(bytesio) as tif:
11104
        assert tif.is_ome
11105
        assert tif.byteorder == '<'
11106
        assert len(tif.pages) == 10
11107
        assert len(tif.series) == 1
11108
        assert 'failed to read' in caplog.text
11109
        # assert page properties
11110
        page = tif.pages.first
11111
        TiffPage._str(page, 4)
11112
        assert page.is_contiguous
11113
        assert page.tags['Software'].value[:15] == 'OME Bio-Formats'
11114
        assert page.compression == COMPRESSION.NONE
11115
        assert page.imagewidth == 512
11116
        assert page.imagelength == 512
11117
        assert page.bitspersample == 8
11118
        assert page.samplesperpixel == 1
11119
        page = tif.pages[-1]
11120
        TiffPage._str(page, 4)
11121
        assert page.shape == (512, 512)
11122
        # assert series properties
11123
        series = tif.series[0]
11124
        assert series.shape == (2, 43, 10, 512, 512)
11125
        assert series.dtype == numpy.uint8
11126
        assert series.axes == 'CTZYX'
11127
        assert series.kind == 'ome'
11128
        assert not series.is_multifile
11129
        # assert data
11130
        data = tif.asarray()
11131
        assert data.shape == (2, 43, 10, 512, 512)
11132
        assert data.dtype == numpy.uint8
11133
        assert data[0, 34, 4, 303, 206] == 82
11134
        assert data[1, 25, 2, 425, 272] == 0
11135
        assert_aszarr_method(tif, data)
11136
        del data
11137
        assert__str__(tif)
11138

11139

11140
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
11141
def test_read_ome_companion(caplog):
11142
    """Test read multifile OME-TIFF using companion file."""
11143
    fname = private_file('OME/companion/multifile-Z2.ome.tiff')
11144
    with TiffFile(fname) as tif:
11145
        assert tif.is_ome
11146
        with caplog.at_level(logging.DEBUG):
11147
            assert tif.series[0].kind == 'generic'
11148
            assert 'OME series is BinaryOnly' in caplog.text
11149

11150
    with open(
11151
        private_file('OME/companion/multifile.companion.ome'), encoding='utf-8'
11152
    ) as fh:
11153
        omexml = fh.read()
11154
    with TiffFile(fname, omexml=omexml) as tif:
11155
        assert tif.is_ome
11156
        series = tif.series[0]
11157
        assert series.kind == 'ome'
11158
        image = series.asarray()
11159

11160
    fname = private_file('OME/companion/multifile-Z1.ome.tiff')
11161
    image2 = imread(fname)
11162
    assert_array_equal(image, image2)
11163

11164

11165
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
11166
def test_read_ome_rgb():
11167
    """Test read OME RGB image."""
11168
    # https://github.com/openmicroscopy/bioformats/pull/1986
11169
    fname = private_file('OME/test_rgb.ome.tif')
11170
    with TiffFile(fname) as tif:
11171
        assert tif.is_ome
11172
        assert tif.byteorder == '<'
11173
        assert len(tif.pages) == 1
11174
        assert len(tif.series) == 1
11175
        # assert page properties
11176
        page = tif.pages.first
11177
        assert page.is_contiguous
11178
        assert page.tags['Software'].value[:15] == 'OME Bio-Formats'
11179
        assert page.compression == COMPRESSION.NONE
11180
        assert page.imagewidth == 1280
11181
        assert page.imagelength == 720
11182
        assert page.bitspersample == 8
11183
        assert page.samplesperpixel == 3
11184
        # assert series properties
11185
        series = tif.series[0]
11186
        assert series.shape == (3, 720, 1280)
11187
        assert series.dtype == numpy.uint8
11188
        assert series.axes == 'SYX'
11189
        assert series.kind == 'ome'
11190
        assert series.dataoffset == 17524
11191
        assert not series.is_multifile
11192
        # assert data
11193
        data = tif.asarray()
11194
        assert data.shape == (3, 720, 1280)
11195
        assert data.dtype == numpy.uint8
11196
        assert data[1, 158, 428] == 253
11197
        assert_aszarr_method(tif, data)
11198
        assert_aszarr_method(tif, data, chunkmode='page')
11199
        assert__str__(tif)
11200

11201

11202
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
11203
def test_read_ome_samplesperpixel():
11204
    """Test read OME image stack with SamplesPerPixel>1."""
11205
    # Reported by Grzegorz Bokota on 2019.1.30
11206
    fname = private_file('OME/test_samplesperpixel.ome.tif')
11207
    with TiffFile(fname) as tif:
11208
        assert tif.is_ome
11209
        assert tif.byteorder == '>'
11210
        assert len(tif.pages) == 6
11211
        assert len(tif.series) == 1
11212
        # assert page properties
11213
        page = tif.pages.first
11214
        assert page.tags['Software'].value[:15] == 'OME Bio-Formats'
11215
        assert page.compression == COMPRESSION.LZW
11216
        assert page.imagewidth == 1024
11217
        assert page.imagelength == 1024
11218
        assert page.bitspersample == 8
11219
        assert page.samplesperpixel == 3
11220
        # assert series properties
11221
        series = tif.series[0]
11222
        assert series.shape == (6, 3, 1024, 1024)
11223
        assert series.dtype == numpy.uint8
11224
        assert series.axes == 'ZSYX'
11225
        assert series.kind == 'ome'
11226
        assert not series.is_multifile
11227
        # assert data
11228
        data = tif.asarray()
11229
        assert data.shape == (6, 3, 1024, 1024)
11230
        assert data.dtype == numpy.uint8
11231
        assert tuple(data[5, :, 191, 449]) == (253, 0, 28)
11232
        assert_aszarr_method(tif, data)
11233
        assert_aszarr_method(tif, data, chunkmode='page')
11234
        assert__str__(tif)
11235

11236

11237
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
11238
def test_read_ome_float_modulo_attributes():
11239
    """Test read OME with floating point modulo attributes."""
11240
    # reported by Start Berg. File by Lorenz Maier.
11241
    fname = private_file('OME/float_modulo_attributes.ome.tiff')
11242
    with TiffFile(fname) as tif:
11243
        assert tif.is_ome
11244
        assert tif.byteorder == '>'
11245
        assert len(tif.pages) == 2
11246
        assert len(tif.series) == 1
11247
        # assert page properties
11248
        page = tif.pages.first
11249
        assert page.is_contiguous
11250
        assert page.tags['Software'].value[:15] == 'OME Bio-Formats'
11251
        assert page.compression == COMPRESSION.NONE
11252
        assert page.imagewidth == 512
11253
        assert page.imagelength == 512
11254
        assert page.bitspersample == 16
11255
        assert page.samplesperpixel == 1
11256
        # assert series properties
11257
        series = tif.series[0]
11258
        assert series.shape == (2, 512, 512)
11259
        assert series.dtype == numpy.uint16
11260
        assert series.axes == 'QYX'
11261
        assert series.kind == 'ome'
11262
        assert not series.is_multifile
11263
        # assert data
11264
        data = tif.asarray()
11265
        assert isinstance(data, numpy.ndarray)
11266
        assert data.shape == (2, 512, 512)
11267
        assert data.dtype == numpy.uint16
11268
        assert data[1, 158, 428] == 51
11269
        assert_aszarr_method(tif, data)
11270
        assert_aszarr_method(tif, data, chunkmode='page')
11271
        assert__str__(tif)
11272

11273

11274
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
11275
def test_read_ome_cropped(caplog):
11276
    """Test read bad OME by ImageJ cropping."""
11277
    # ImageJ produces invalid ome-xml when cropping
11278
    # http://lists.openmicroscopy.org.uk/pipermail/ome-devel/2013-December
11279
    #  /002631.html
11280
    # Reported by Hadrien Mary on Dec 11, 2013
11281
    fname = private_file('ome/cropped.ome.tif')
11282
    with TiffFile(fname) as tif:
11283
        assert tif.is_ome
11284
        assert tif.byteorder == '<'
11285
        assert len(tif.pages) == 100
11286
        assert len(tif.series) == 1
11287
        assert 'invalid TiffData index' in caplog.text
11288
        # assert page properties
11289
        page = tif.pages.first
11290
        assert page.tags['Software'].value[:15] == 'OME Bio-Formats'
11291
        assert page.imagewidth == 324
11292
        assert page.imagelength == 249
11293
        assert page.bitspersample == 16
11294
        # assert series properties
11295
        series = tif.series[0]
11296
        assert series.shape == (5, 10, 2, 249, 324)
11297
        assert series.dtype == numpy.uint16
11298
        assert series.axes == 'TZCYX'
11299
        assert series.kind == 'ome'
11300
        assert not series.is_multifile
11301
        # assert data
11302
        data = tif.asarray()
11303
        assert data.shape == (5, 10, 2, 249, 324)
11304
        assert data.dtype == numpy.uint16
11305
        assert data[4, 9, 1, 175, 123] == 9605
11306
        assert_aszarr_method(tif, data)
11307
        assert_aszarr_method(tif, data, chunkmode='page')
11308
        del data
11309
        assert__str__(tif)
11310

11311

11312
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS or SKIP_LARGE, reason=REASON)
11313
def test_read_ome_corrupted_page(caplog):
11314
    """Test read OME with corrupted but not referenced page."""
11315
    # https://forum.image.sc/t/qupath-0-2-0-not-able-to-open-ome-tiff/23821/3
11316
    fname = private_file('ome/2019_02_19__7760_s1.ome.tiff')
11317
    with TiffFile(fname) as tif:
11318
        assert tif.is_ome
11319
        assert tif.is_bigtiff
11320
        assert tif.byteorder == '<'
11321
        assert len(tif.pages) == 5
11322
        assert len(tif.series) == 1
11323
        assert 'missing required tags' in caplog.text
11324
        # assert page properties
11325
        page = tif.pages.first
11326
        assert page.imagewidth == 7506
11327
        assert page.imagelength == 7506
11328
        assert page.bitspersample == 16
11329
        # assert series properties
11330
        series = tif.series[0]
11331
        assert series.shape == (4, 7506, 7506)
11332
        assert series.dtype == numpy.uint16
11333
        assert series.axes == 'CYX'
11334
        assert series.kind == 'ome'
11335
        assert not series.is_multifile
11336
        # assert data
11337
        data = tif.asarray()
11338
        assert data.shape == (4, 7506, 7506)
11339
        assert data.dtype == numpy.uint16
11340
        assert tuple(data[:, 2684, 2684]) == (496, 657, 7106, 469)
11341
        assert_aszarr_method(tif, data)
11342
        assert_aszarr_method(tif, data, chunkmode='page')
11343
        del data
11344
        assert__str__(tif)
11345

11346

11347
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
11348
def test_read_ome_nikon():
11349
    """Test read bad OME by Nikon."""
11350
    # OME-XML references only first image
11351
    # received from E. Gratton
11352
    fname = private_file('OME/Nikon-cell011.ome.tif')
11353
    with TiffFile(fname) as tif:
11354
        assert tif.is_ome
11355
        assert tif.byteorder == '<'
11356
        assert len(tif.pages) == 1000
11357
        assert len(tif.series) == 1
11358
        # assert 'index out of range' in caplog.text
11359
        # assert page properties
11360
        page = tif.pages.first
11361
        assert page.photometric != PHOTOMETRIC.RGB
11362
        assert page.imagewidth == 1982
11363
        assert page.imagelength == 1726
11364
        assert page.bitspersample == 16
11365
        assert page.is_contiguous
11366
        assert (
11367
            page.tags['ImageLength'].offset - page.tags['ImageWidth'].offset
11368
            == 20
11369
        )
11370
        assert page.tags['ImageWidth'].offset == 6856262146
11371
        assert page.tags['ImageWidth'].valueoffset == 6856262158
11372
        assert page.tags['ImageLength'].offset == 6856262166
11373
        assert page.tags['ImageLength'].valueoffset == 6856262178
11374
        assert page.tags['StripByteCounts'].offset == 6856262366
11375
        assert page.tags['StripByteCounts'].valueoffset == 6856262534
11376
        # assert series properties
11377
        series = tif.series[0]
11378
        assert len(series._pages) == 1
11379
        assert len(series.pages) == 1
11380
        assert series.dataoffset == 16  # contiguous
11381
        assert series.shape == (1726, 1982)
11382
        assert series.dtype == numpy.uint16
11383
        assert series.axes == 'YX'
11384
        assert series.kind == 'ome'
11385
        assert__str__(tif)
11386

11387
    with TiffFile(fname, is_ome=False) as tif:
11388
        assert not tif.is_ome
11389
        # assert series properties
11390
        series = tif.series[0]
11391
        assert len(series.pages) == 1000
11392
        assert series.dataoffset is None  # not contiguous
11393
        assert series.shape == (1000, 1726, 1982)
11394
        assert series.dtype == numpy.uint16
11395
        assert series.axes == 'IYX'
11396
        assert series.kind == 'uniform'
11397
        assert__str__(tif)
11398

11399

11400
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
11401
def test_read_ome_shape_mismatch(caplog):
11402
    """Test read OME with page shape mismatch."""
11403
    # TCX (20000, 2, 500) is stored in 2 pages of (20000, 500)
11404
    # probably exported by ZEN Software
11405
    fname = private_file('OME/Image 7.ome_h00.tiff')
11406
    with TiffFile(fname) as tif:
11407
        assert tif.is_ome
11408
        assert tif.byteorder == '<'
11409
        assert len(tif.pages) == 2
11410
        assert len(tif.series) == 2
11411
        assert 'cannot handle discontiguous storage' in caplog.text
11412
        # assert page properties
11413
        page = tif.pages.first
11414
        assert page.is_contiguous
11415
        assert page.photometric == PHOTOMETRIC.MINISBLACK
11416
        assert page.imagewidth == 500
11417
        assert page.imagelength == 20000
11418
        assert page.bitspersample == 16
11419
        assert page.samplesperpixel == 1
11420
        page = tif.pages[1]
11421
        assert page.is_contiguous
11422
        assert page.photometric == PHOTOMETRIC.PALETTE
11423
        assert page.imagewidth == 500
11424
        assert page.imagelength == 20000
11425
        assert page.bitspersample == 8
11426
        assert page.samplesperpixel == 1
11427
        # assert series properties
11428
        series = tif.series[0]
11429
        assert series.shape == (20000, 500)
11430
        assert series.dtype == numpy.uint16
11431
        assert series.axes == 'YX'
11432
        assert series.dataoffset == 8
11433
        assert series.kind == 'generic'
11434

11435

11436
@pytest.mark.skipif(
11437
    SKIP_PRIVATE or SKIP_CODECS or not imagecodecs.JPEG2K.available,
11438
    reason=REASON,
11439
)
11440
def test_read_ome_jpeg2000_be():
11441
    """Test read JPEG2000 compressed big-endian OME-TIFF."""
11442
    fname = private_file('OME/mitosis.jpeg2000.ome.tif')
11443
    with TiffFile(fname) as tif:
11444
        assert tif.is_ome
11445
        assert tif.byteorder == '>'
11446
        assert len(tif.pages) == 510
11447
        assert len(tif.series) == 1
11448
        # assert page properties
11449
        page = tif.pages.first
11450
        assert not page.is_contiguous
11451
        assert page.tags['Software'].value[:15] == 'OME Bio-Formats'
11452
        assert page.compression == COMPRESSION.APERIO_JP2000_YCBC
11453
        assert page.imagewidth == 171
11454
        assert page.imagelength == 196
11455
        assert page.bitspersample == 16
11456
        assert page.samplesperpixel == 1
11457
        # assert series properties
11458
        series = tif.series[0]
11459
        assert series.shape == (51, 5, 2, 196, 171)
11460
        assert series.dtype == numpy.uint16
11461
        assert series.axes == 'TZCYX'
11462
        assert series.kind == 'ome'
11463
        # assert data
11464
        data = page.asarray()
11465
        assert isinstance(data, numpy.ndarray)
11466
        assert data.shape == (196, 171)
11467
        assert data.dtype == numpy.uint16
11468
        assert data[0, 0] == 1904
11469
        assert_aszarr_method(page, data)
11470
        assert_aszarr_method(page, data, chunkmode='page')
11471
        assert__str__(tif)
11472

11473

11474
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
11475
def test_read_ome_samplesperpixel_mismatch(caplog):
11476
    """Test read OME with SamplesPerPixel mismatch: OME=1, TIFF=4."""
11477
    # https://forum.image.sc/t/ilastik-refuses-to-load-image-file/48541/1
11478
    fname = private_file('OME/MismatchSamplesPerPixel.ome.tif')
11479
    with TiffFile(fname) as tif:
11480
        assert tif.is_ome
11481
        assert tif.byteorder == '<'
11482
        assert len(tif.pages) == 1
11483
        assert len(tif.series) == 1
11484
        # assert page properties
11485
        page = tif.pages.first
11486
        assert page.photometric == PHOTOMETRIC.RGB
11487
        assert page.compression == COMPRESSION.LZW
11488
        assert page.imagewidth == 2080
11489
        assert page.imagelength == 1552
11490
        assert page.bitspersample == 8
11491
        assert page.samplesperpixel == 4
11492
        # assert series properties
11493
        series = tif.series[0]
11494
        assert 'cannot handle discontiguous storage' in caplog.text
11495
        assert series.shape == (1552, 2080, 4)
11496
        assert series.dtype == numpy.uint8
11497
        assert series.axes == 'YXS'
11498
        assert series.kind == 'generic'  # ome series failed
11499
        assert not series.is_multifile
11500
        # assert data
11501
        data = tif.asarray()
11502
        assert data.shape == (1552, 2080, 4)
11503
        assert_aszarr_method(tif, data)
11504
        assert__str__(tif)
11505

11506

11507
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_ZARR, reason=REASON)
11508
@pytest.mark.parametrize('chunkmode', [0, 2])
11509
def test_read_ome_multiscale(chunkmode):
11510
    """Test read pyramidal OME file."""
11511
    fname = public_file('tifffile/multiscene_pyramidal.ome.tif')
11512
    with TiffFile(fname) as tif:
11513
        assert tif.is_ome
11514
        assert tif.byteorder == '<'
11515
        assert len(tif.pages) == 1025
11516
        assert len(tif.series) == 2
11517
        # assert page properties
11518
        page = tif.pages.first
11519
        assert page.photometric == PHOTOMETRIC.MINISBLACK
11520
        assert page.compression == COMPRESSION.ADOBE_DEFLATE
11521
        assert page.imagewidth == 256
11522
        assert page.imagelength == 256
11523
        assert page.bitspersample == 8
11524
        assert page.samplesperpixel == 1
11525
        # assert series properties
11526
        series = tif.series[0]
11527
        assert series.kind == 'ome'
11528
        assert series.shape == (16, 32, 2, 256, 256)
11529
        assert series.dtype == numpy.uint8
11530
        assert series.axes == 'TZCYX'
11531
        assert series.is_pyramidal
11532
        assert not series.is_multifile
11533
        series = tif.series[1]
11534
        assert series.kind == 'ome'
11535
        assert series.shape == (128, 128, 3)
11536
        assert series.dtype == numpy.uint8
11537
        assert series.axes == 'YXS'
11538
        assert not series.is_pyramidal
11539
        assert not series.is_multifile
11540
        # assert data
11541
        data = tif.asarray()
11542
        assert data.shape == (16, 32, 2, 256, 256)
11543
        assert_aszarr_method(tif, data, chunkmode=chunkmode)
11544
        assert__str__(tif)
11545

11546

11547
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
11548
def test_read_andor_light_sheet_512p():
11549
    """Test read Andor."""
11550
    # 12113x13453, uint16
11551
    fname = private_file('andor/light sheet 512px.tif')
11552
    with TiffFile(fname) as tif:
11553
        assert tif.byteorder == '<'
11554
        assert len(tif.pages) == 100
11555
        assert len(tif.series) == 1
11556
        assert tif.is_andor
11557
        # assert page properties
11558
        page = tif.pages.first
11559
        assert page.is_andor
11560
        assert page.is_contiguous
11561
        assert page.compression == COMPRESSION.NONE
11562
        assert page.imagewidth == 512
11563
        assert page.imagelength == 512
11564
        assert page.bitspersample == 16
11565
        assert page.samplesperpixel == 1
11566
        # assert metadata
11567
        t = page.andor_tags
11568
        assert t['SoftwareVersion'] == '4.23.30014.0'
11569
        assert t['Frames'] == 100.0
11570
        # assert series properties
11571
        series = tif.series[0]
11572
        assert series.shape == (100, 512, 512)
11573
        assert series.dtype == numpy.uint16
11574
        assert series.axes == 'IYX'
11575
        assert series.kind == 'uniform'
11576
        assert isinstance(series.pages[2], TiffFrame)
11577
        # assert data
11578
        data = tif.asarray()
11579
        assert data.shape == (100, 512, 512)
11580
        assert data.dtype == numpy.uint16
11581
        assert round(abs(data[50, 256, 256] - 703), 7) == 0
11582
        assert_aszarr_method(tif, data)
11583
        assert_aszarr_method(tif, data, chunkmode='page')
11584
        assert__str__(tif, 0)
11585

11586

11587
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
11588
def test_read_nih_morph():
11589
    """Test read NIH."""
11590
    # 388x252 uint8
11591
    fname = private_file('nihimage/morph.tiff')
11592
    with TiffFile(fname) as tif:
11593
        assert tif.is_nih
11594
        assert tif.byteorder == '>'
11595
        assert len(tif.pages) == 1
11596
        assert len(tif.series) == 1
11597
        # assert page properties
11598
        page = tif.pages.first
11599
        assert page.imagewidth == 388
11600
        assert page.imagelength == 252
11601
        assert page.bitspersample == 8
11602
        # assert series properties
11603
        series = tif.series[0]
11604
        assert series.kind == 'nih'
11605
        assert series.shape == (252, 388)
11606
        assert series.dtype == numpy.uint8
11607
        assert series.axes == 'YX'
11608
        # assert NIH tags
11609
        tags = tif.nih_metadata
11610
        assert tags['FileID'] == 'IPICIMAG'
11611
        assert tags['PixelsPerLine'] == 388
11612
        assert tags['nLines'] == 252
11613
        assert tags['ForegroundIndex'] == 255
11614
        # assert data
11615
        data = tif.asarray()
11616
        assert isinstance(data, numpy.ndarray)
11617
        assert data.shape == (252, 388)
11618
        assert data.dtype == numpy.uint8
11619
        assert data[195, 144] == 41
11620
        assert_aszarr_method(tif, data)
11621
        assert_aszarr_method(tif, data, chunkmode='page')
11622
        assert__str__(tif)
11623

11624

11625
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
11626
def test_read_nih_silver_lake():
11627
    """Test read NIH palette."""
11628
    # 259x187 16 bit palette
11629
    fname = private_file('nihimage/silver lake.tiff')
11630
    with TiffFile(fname) as tif:
11631
        assert tif.is_nih
11632
        assert tif.byteorder == '>'
11633
        assert len(tif.pages) == 1
11634
        assert len(tif.series) == 1
11635
        # assert page properties
11636
        page = tif.pages.first
11637
        assert page.is_contiguous
11638
        assert page.photometric == PHOTOMETRIC.PALETTE
11639
        assert page.imagewidth == 259
11640
        assert page.imagelength == 187
11641
        assert page.bitspersample == 8
11642
        # assert series properties
11643
        series = tif.series[0]
11644
        assert series.kind == 'nih'
11645
        assert series.shape == (187, 259)
11646
        assert series.dtype == numpy.uint8
11647
        assert series.axes == 'YX'
11648
        # assert NIH tags
11649
        tags = tif.nih_metadata
11650
        assert tags['FileID'] == 'IPICIMAG'
11651
        assert tags['PixelsPerLine'] == 259
11652
        assert tags['nLines'] == 187
11653
        assert tags['ForegroundIndex'] == 109
11654
        # assert data
11655
        data = page.asrgb()
11656
        assert isinstance(data, numpy.ndarray)
11657
        assert data.shape == (187, 259, 3)
11658
        assert data.dtype == numpy.uint16
11659
        assert tuple(data[86, 102, :]) == (26214, 39321, 39321)
11660
        assert__str__(tif)
11661

11662

11663
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
11664
def test_read_nih_scala_media():
11665
    """Test read multi-page NIH."""
11666
    # 36x54x84 palette
11667
    fname = private_file('nihimage/scala-media.tif')
11668
    with TiffFile(fname) as tif:
11669
        assert tif.is_nih
11670
        assert tif.byteorder == '>'
11671
        assert len(tif.pages) == 36
11672
        assert len(tif.series) == 1
11673
        # assert page properties
11674
        page = tif.pages.first
11675
        assert page.is_contiguous
11676
        assert page.photometric == PHOTOMETRIC.PALETTE
11677
        assert page.imagewidth == 84
11678
        assert page.imagelength == 54
11679
        assert page.bitspersample == 8
11680
        # assert series properties
11681
        series = tif.series[0]
11682
        assert series.kind == 'nih'
11683
        assert series.shape == (36, 54, 84)
11684
        assert series.dtype == numpy.uint8
11685
        assert series.axes == 'IYX'
11686
        # assert NIH tags
11687
        tags = tif.nih_metadata
11688
        assert tags['Version'] == 160
11689
        assert tags['nLines'] == 54
11690
        # assert data
11691
        data = tif.asarray()
11692
        assert isinstance(data, numpy.ndarray)
11693
        assert data.shape == (36, 54, 84)
11694
        assert data.dtype == numpy.uint8
11695
        assert data[35, 35, 65] == 171
11696
        assert_aszarr_method(tif, data)
11697
        assert_aszarr_method(tif, data, chunkmode='page')
11698
        assert__str__(tif)
11699

11700

11701
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_CODECS, reason=REASON)
11702
def test_read_imagej_rrggbb():
11703
    """Test read planar RGB ImageJ file created by Bio-Formats."""
11704
    fname = public_file('tifffile/rrggbb.ij.tif')
11705
    with TiffFile(fname) as tif:
11706
        assert tif.is_imagej
11707
        assert tif.byteorder == '<'
11708
        assert len(tif.pages) == 1
11709
        assert len(tif.series) == 1
11710
        # assert page properties
11711
        page = tif.pages.first
11712
        assert page.photometric == PHOTOMETRIC.RGB
11713
        assert page.compression == COMPRESSION.LZW
11714
        assert page.imagewidth == 31
11715
        assert page.imagelength == 32
11716
        assert page.bitspersample == 16
11717
        # assert series properties
11718
        series = tif.series[0]
11719
        assert series.kind == 'imagej'
11720
        assert series.dtype == numpy.uint16
11721
        assert series.shape == (3, 32, 31)
11722
        assert series.axes == 'CYX'
11723
        assert series.get_shape(False) == (1, 1, 3, 32, 31, 1)
11724
        assert series.get_axes(False) == 'TZCYXS'
11725
        assert len(series._pages) == 1
11726
        assert len(series.pages) == 1
11727
        # assert ImageJ tags
11728
        ijmeta = tif.imagej_metadata
11729
        assert ijmeta is not None
11730
        assert ijmeta['ImageJ'] == ''
11731
        assert ijmeta['images'] == 3
11732
        assert ijmeta['channels'] == 3
11733
        assert ijmeta['slices'] == 1
11734
        assert ijmeta['frames'] == 1
11735
        assert ijmeta['hyperstack']
11736
        # assert data
11737
        data = tif.asarray()
11738
        assert isinstance(data, numpy.ndarray)
11739
        assert data.shape == (3, 32, 31)
11740
        assert data.dtype == numpy.uint16
11741
        assert tuple(data[:, 15, 15]) == (812, 1755, 648)
11742
        assert_decode_method(page)
11743
        assert_aszarr_method(series, data)
11744
        assert_aszarr_method(series, data, chunkmode='page')
11745
        # don't squeeze
11746
        data = tif.asarray(squeeze=False)
11747
        assert data.shape == (1, 1, 3, 32, 31, 1)
11748
        assert_aszarr_method(series, data, squeeze=False)
11749
        assert__str__(tif, 0)
11750

11751

11752
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
11753
def test_read_imagej_focal1():
11754
    """Test read ImageJ 205x434x425 uint8."""
11755
    fname = private_file('imagej/focal1.tif')
11756
    with TiffFile(fname) as tif:
11757
        assert tif.is_imagej
11758
        assert tif.byteorder == '>'
11759
        assert len(tif.pages) == 205
11760
        assert len(tif.series) == 1
11761
        # assert page properties
11762
        page = tif.pages.first
11763
        assert page.photometric != PHOTOMETRIC.RGB
11764
        assert page.imagewidth == 425
11765
        assert page.imagelength == 434
11766
        assert page.bitspersample == 8
11767
        assert page.is_contiguous
11768
        # assert series properties
11769
        series = tif.series[0]
11770
        assert series.kind == 'imagej'
11771
        assert series.dataoffset == 768
11772
        assert series.shape == (205, 434, 425)
11773
        assert series.dtype == numpy.uint8
11774
        assert series.axes == 'IYX'
11775
        assert series.get_shape(False) == (205, 1, 1, 1, 434, 425, 1)
11776
        assert series.get_axes(False) == 'ITZCYXS'
11777
        assert len(series._pages) == 1
11778
        assert len(series.pages) == 205
11779
        # assert ImageJ tags
11780
        ijmeta = tif.imagej_metadata
11781
        assert ijmeta is not None
11782
        assert ijmeta['ImageJ'] == '1.34k'
11783
        assert ijmeta['images'] == 205
11784
        # assert data
11785
        data = tif.asarray()
11786
        assert isinstance(data, numpy.ndarray)
11787
        assert data.shape == (205, 434, 425)
11788
        assert data.dtype == numpy.uint8
11789
        assert data[102, 216, 212] == 120
11790
        assert_aszarr_method(series, data)
11791
        assert_aszarr_method(series, data, chunkmode='page')
11792
        assert__str__(tif, 0)
11793

11794

11795
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
11796
def test_read_imagej_hela_cells():
11797
    """Test read ImageJ 512x672 RGB uint16."""
11798
    fname = private_file('imagej/hela-cells.tif')
11799
    with TiffFile(fname) as tif:
11800
        assert tif.is_imagej
11801
        assert tif.byteorder == '>'
11802
        assert len(tif.pages) == 1
11803
        assert len(tif.series) == 1
11804
        # assert page properties
11805
        page = tif.pages.first
11806
        assert page.photometric == PHOTOMETRIC.RGB
11807
        assert page.imagewidth == 672
11808
        assert page.imagelength == 512
11809
        assert page.bitspersample == 16
11810
        assert page.is_contiguous
11811
        # assert series properties
11812
        series = tif.series[0]
11813
        assert series.kind == 'imagej'
11814
        assert series.shape == (512, 672, 3)
11815
        assert series.dtype == numpy.uint16
11816
        assert series.axes == 'YXS'
11817
        assert series.get_shape(False) == (1, 1, 1, 512, 672, 3)
11818
        assert series.get_axes(False) == 'TZCYXS'
11819
        # assert ImageJ tags
11820
        ijmeta = tif.imagej_metadata
11821
        assert ijmeta is not None
11822
        assert ijmeta['ImageJ'] == '1.46i'
11823
        assert ijmeta['channels'] == 3
11824
        # assert data
11825
        data = tif.asarray()
11826
        assert isinstance(data, numpy.ndarray)
11827
        assert data.shape == (512, 672, 3)
11828
        assert data.dtype == numpy.uint16
11829
        assert tuple(data[255, 336]) == (440, 378, 298)
11830
        assert_aszarr_method(series, data)
11831
        assert_aszarr_method(series, data, chunkmode='page')
11832
        # don't squeeze
11833
        data = tif.asarray(squeeze=False)
11834
        assert data.shape == (1, 1, 1, 512, 672, 3)
11835
        assert_aszarr_method(series, data, squeeze=False)
11836
        assert__str__(tif)
11837

11838

11839
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
11840
def test_read_imagej_flybrain():
11841
    """Test read ImageJ 57x256x256 RGB."""
11842
    fname = private_file('imagej/flybrain.tif')
11843
    with TiffFile(fname) as tif:
11844
        assert tif.is_imagej
11845
        assert tif.byteorder == '>'
11846
        assert len(tif.pages) == 57
11847
        assert len(tif.series) == 1  # hyperstack
11848
        # assert page properties
11849
        page = tif.pages.first
11850
        assert page.photometric == PHOTOMETRIC.RGB
11851
        assert page.imagewidth == 256
11852
        assert page.imagelength == 256
11853
        assert page.bitspersample == 8
11854
        # assert series properties
11855
        series = tif.series[0]
11856
        assert series.kind == 'imagej'
11857
        assert series.shape == (57, 256, 256, 3)
11858
        assert series.dtype == numpy.uint8
11859
        assert series.axes == 'ZYXS'
11860
        assert series.get_shape(False) == (1, 57, 1, 256, 256, 3)
11861
        assert series.get_axes(False) == 'TZCYXS'
11862
        # assert ImageJ tags
11863
        ijmeta = tif.imagej_metadata
11864
        assert ijmeta is not None
11865
        assert ijmeta['ImageJ'] == '1.43d'
11866
        assert ijmeta['slices'] == 57
11867
        # assert data
11868
        data = tif.asarray()
11869
        assert isinstance(data, numpy.ndarray)
11870
        assert data.shape == (57, 256, 256, 3)
11871
        assert data.dtype == numpy.uint8
11872
        assert tuple(data[18, 108, 97]) == (165, 157, 0)
11873
        assert_aszarr_method(series, data)
11874
        assert_aszarr_method(series, data, chunkmode='page')
11875
        # don't squeeze
11876
        data = tif.asarray(squeeze=False)
11877
        assert data.shape == (1, 57, 1, 256, 256, 3)
11878
        assert_aszarr_method(series, data, squeeze=False)
11879
        assert__str__(tif)
11880

11881

11882
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
11883
def test_read_imagej_confocal_series():
11884
    """Test read ImageJ 25x2x400x400 ZCYX."""
11885
    fname = private_file('imagej/confocal-series.tif')
11886
    with TiffFile(fname) as tif:
11887
        assert tif.is_imagej
11888
        assert tif.byteorder == '>'
11889
        assert len(tif.pages) == 50
11890
        assert len(tif.series) == 1  # hyperstack
11891
        # assert page properties
11892
        page = tif.pages.first
11893
        assert page.imagewidth == 400
11894
        assert page.imagelength == 400
11895
        assert page.bitspersample == 8
11896
        assert page.is_contiguous
11897
        # assert series properties
11898
        series = tif.series[0]
11899
        assert series.kind == 'imagej'
11900
        assert series.shape == (25, 2, 400, 400)
11901
        assert series.dtype == numpy.uint8
11902
        assert series.axes == 'ZCYX'
11903
        assert len(series._pages) == 1
11904
        assert len(series.pages) == 50
11905
        # assert ImageJ tags
11906
        ijmeta = tif.imagej_metadata
11907
        assert ijmeta is not None
11908
        assert ijmeta['ImageJ'] == '1.43d'
11909
        assert ijmeta['images'] == len(tif.pages)
11910
        assert ijmeta['channels'] == 2
11911
        assert ijmeta['slices'] == 25
11912
        assert ijmeta['hyperstack']
11913
        # assert data
11914
        data = tif.asarray()
11915
        assert isinstance(data, numpy.ndarray)
11916
        assert data.shape == (25, 2, 400, 400)
11917
        assert data.dtype == numpy.uint8
11918
        assert tuple(data[12, :, 100, 300]) == (6, 66)
11919
        # assert only two pages are loaded
11920
        with pytest.warns(DeprecationWarning):
11921
            assert isinstance(tif.pages.pages[0], TiffPage)
11922
        assert isinstance(tif.pages._pages[0], TiffPage)
11923
        if tif.pages.cache:
11924
            assert isinstance(tif.pages._pages[1], TiffFrame)
11925
        else:
11926
            assert tif.pages._pages[1] == 8000911
11927
        assert tif.pages._pages[2] == 8001073
11928
        assert tif.pages._pages[-1] == 8008687
11929
        assert_aszarr_method(series, data)
11930
        assert_aszarr_method(series, data, chunkmode='page')
11931
        # don't squeeze
11932
        data = tif.asarray(squeeze=False)
11933
        assert data.shape == (1, 25, 2, 400, 400, 1)
11934
        assert_aszarr_method(series, data, squeeze=False)
11935
        assert__str__(tif)
11936

11937

11938
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
11939
def test_read_imagej_graphite():
11940
    """Test read ImageJ 1024x593 float32."""
11941
    fname = private_file('imagej/graphite1-1024.tif')
11942
    with TiffFile(fname) as tif:
11943
        assert tif.is_imagej
11944
        assert tif.byteorder == '>'
11945
        assert len(tif.pages) == 1
11946
        assert len(tif.series) == 1
11947
        # assert page properties
11948
        page = tif.pages.first
11949
        assert page.imagewidth == 1024
11950
        assert page.imagelength == 593
11951
        assert page.bitspersample == 32
11952
        assert page.is_contiguous
11953
        # assert series properties
11954
        series = tif.series[0]
11955
        assert series.kind == 'imagej'
11956
        assert len(series._pages) == 1
11957
        assert len(series.pages) == 1
11958
        assert series.shape == (593, 1024)
11959
        assert series.dtype == numpy.float32
11960
        assert series.axes == 'YX'
11961
        # assert ImageJ tags
11962
        ijmeta = tif.imagej_metadata
11963
        assert ijmeta is not None
11964
        assert ijmeta['ImageJ'] == '1.47t'
11965
        assert round(abs(ijmeta['max'] - 1686.10949707), 7) == 0
11966
        assert round(abs(ijmeta['min'] - 852.08605957), 7) == 0
11967
        # assert data
11968
        data = tif.asarray()
11969
        assert isinstance(data, numpy.ndarray)
11970
        assert data.shape == (593, 1024)
11971
        assert data.dtype == numpy.float32
11972
        assert round(abs(data[443, 656] - 2203.040771484375), 7) == 0
11973
        assert_aszarr_method(series, data)
11974
        # don't squeeze
11975
        data = tif.asarray(squeeze=False)
11976
        assert data.shape == (1, 1, 1, 593, 1024, 1)
11977
        assert_aszarr_method(series, data, squeeze=False)
11978
        assert__str__(tif)
11979

11980

11981
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
11982
def test_read_imagej_bat_cochlea_volume():
11983
    """Test read ImageJ 114 images, no frames, slices, channels specified."""
11984
    fname = private_file('imagej/bat-cochlea-volume.tif')
11985
    with TiffFile(fname) as tif:
11986
        assert tif.is_imagej
11987
        assert tif.byteorder == '>'
11988
        assert len(tif.pages) == 114
11989
        assert len(tif.series) == 1
11990
        # assert page properties
11991
        page = tif.pages.first
11992
        assert page.photometric != PHOTOMETRIC.RGB
11993
        assert page.imagewidth == 121
11994
        assert page.imagelength == 154
11995
        assert page.bitspersample == 8
11996
        assert page.is_contiguous
11997
        # assert series properties
11998
        series = tif.series[0]
11999
        assert series.kind == 'imagej'
12000
        assert len(series._pages) == 1
12001
        assert len(series.pages) == 114
12002
        assert series.shape == (114, 154, 121)
12003
        assert series.dtype == numpy.uint8
12004
        assert series.axes == 'IYX'
12005
        # assert ImageJ tags
12006
        ijmeta = tif.imagej_metadata
12007
        assert ijmeta is not None
12008
        assert ijmeta['ImageJ'] == '1.20n'
12009
        assert ijmeta['images'] == 114
12010
        # assert data
12011
        data = tif.asarray()
12012
        assert isinstance(data, numpy.ndarray)
12013
        assert data.shape == (114, 154, 121)
12014
        assert data.dtype == numpy.uint8
12015
        assert data[113, 97, 61] == 255
12016
        assert_aszarr_method(series, data)
12017
        # don't squeeze
12018
        data = tif.asarray(squeeze=False)
12019
        assert data.shape == (114, 1, 1, 1, 154, 121, 1)
12020
        assert_aszarr_method(series, data, squeeze=False)
12021
        assert__str__(tif)
12022

12023

12024
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
12025
def test_read_imagej_first_instar_brain():
12026
    """Test read ImageJ 56x256x256x3 ZYXS."""
12027
    fname = private_file('imagej/first-instar-brain.tif')
12028
    with TiffFile(fname) as tif:
12029
        assert tif.is_imagej
12030
        assert tif.byteorder == '>'
12031
        assert len(tif.pages) == 56
12032
        assert len(tif.series) == 1
12033
        # assert page properties
12034
        page = tif.pages.first
12035
        assert page.photometric == PHOTOMETRIC.RGB
12036
        assert page.imagewidth == 256
12037
        assert page.imagelength == 256
12038
        assert page.bitspersample == 8
12039
        assert page.is_contiguous
12040
        # assert series properties
12041
        series = tif.series[0]
12042
        assert series.kind == 'imagej'
12043
        assert len(series._pages) == 1
12044
        assert len(series.pages) == 56
12045
        assert series.shape == (56, 256, 256, 3)
12046
        assert series.dtype == numpy.uint8
12047
        assert series.axes == 'ZYXS'
12048
        # assert ImageJ tags
12049
        ijmeta = tif.imagej_metadata
12050
        assert ijmeta is not None
12051
        assert ijmeta['ImageJ'] == '1.44j'
12052
        assert ijmeta['images'] == 56
12053
        assert ijmeta['slices'] == 56
12054
        # assert data
12055
        data = tif.asarray()
12056
        assert isinstance(data, numpy.ndarray)
12057
        assert data.shape == (56, 256, 256, 3)
12058
        assert data.dtype == numpy.uint8
12059
        assert tuple(data[55, 151, 112]) == (209, 8, 58)
12060
        assert_aszarr_method(series, data)
12061
        assert__str__(tif)
12062

12063

12064
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
12065
def test_read_imagej_fluorescentcells():
12066
    """Test read ImageJ three channels."""
12067
    fname = private_file('imagej/FluorescentCells.tif')
12068
    with TiffFile(fname) as tif:
12069
        assert tif.is_imagej
12070
        assert tif.byteorder == '>'
12071
        assert len(tif.pages) == 3
12072
        assert len(tif.series) == 1
12073
        # assert page properties
12074
        page = tif.pages.first
12075
        assert page.photometric == PHOTOMETRIC.PALETTE
12076
        assert page.imagewidth == 512
12077
        assert page.imagelength == 512
12078
        assert page.bitspersample == 8
12079
        assert page.is_contiguous
12080
        # assert series properties
12081
        series = tif.series[0]
12082
        assert series.kind == 'imagej'
12083
        assert series.shape == (3, 512, 512)
12084
        assert series.dtype == numpy.uint8
12085
        assert series.axes == 'CYX'
12086
        # assert ImageJ tags
12087
        ijmeta = tif.imagej_metadata
12088
        assert ijmeta is not None
12089
        assert ijmeta['ImageJ'] == '1.40c'
12090
        assert ijmeta['images'] == 3
12091
        assert ijmeta['channels'] == 3
12092
        # assert data
12093
        data = tif.asarray()
12094
        assert isinstance(data, numpy.ndarray)
12095
        assert data.shape == (3, 512, 512)
12096
        assert data.dtype == numpy.uint8
12097
        assert tuple(data[:, 256, 256]) == (57, 120, 13)
12098
        assert_aszarr_method(series, data)
12099
        assert__str__(tif)
12100

12101

12102
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_LARGE, reason=REASON)
12103
def test_read_imagej_100000_pages():
12104
    """Test read ImageJ with 100000 pages."""
12105
    # 100000x64x64
12106
    # file is big endian, memory mapped
12107
    fname = public_file('tifffile/100000_pages.tif')
12108
    with TiffFile(fname) as tif:
12109
        assert tif.is_imagej
12110
        assert tif.byteorder == '>'
12111
        assert len(tif.pages) == 100000
12112
        assert len(tif.series) == 1
12113
        # assert page properties
12114
        page = tif.pages.first
12115
        assert page.imagewidth == 64
12116
        assert page.imagelength == 64
12117
        assert page.bitspersample == 16
12118
        assert page.is_contiguous
12119
        # assert series properties
12120
        series = tif.series[0]
12121
        assert series.kind == 'imagej'
12122
        assert len(series._pages) == 1
12123
        assert len(series.pages) == 100000
12124
        assert series.shape == (100000, 64, 64)
12125
        assert series.dtype == numpy.uint16
12126
        assert series.axes == 'TYX'
12127
        # assert ImageJ tags
12128
        ijmeta = tif.imagej_metadata
12129
        assert ijmeta is not None
12130
        assert ijmeta['ImageJ'] == '1.48g'
12131
        assert round(abs(ijmeta['max'] - 119.0), 7) == 0
12132
        assert round(abs(ijmeta['min'] - 86.0), 7) == 0
12133
        # assert data
12134
        data = tif.asarray(out='memmap')
12135
        assert isinstance(data, numpy.memmap)
12136
        assert data.shape == (100000, 64, 64)
12137
        assert data.dtype == numpy.dtype('>u2')
12138
        assert round(abs(data[7310, 25, 25] - 100), 7) == 0
12139
        # too slow: assert_aszarr_method(series, data)
12140
        assert__str__(tif, 0)
12141
        del data
12142

12143

12144
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
12145
def test_read_imagej_invalid_metadata(caplog):
12146
    """Test read bad ImageJ metadata."""
12147
    # file contains 1 page but metadata claims 3500 images
12148
    # memory map big endian data
12149
    fname = private_file('sima/0.tif')
12150
    with TiffFile(fname) as tif:
12151
        assert tif.is_imagej
12152
        assert tif.byteorder == '>'
12153
        assert len(tif.pages) == 1
12154
        assert len(tif.series) == 1
12155
        assert 'ImageJ series metadata invalid or corrupted' in caplog.text
12156
        # assert page properties
12157
        page = tif.pages.first
12158
        assert page.photometric != PHOTOMETRIC.RGB
12159
        assert page.imagewidth == 173
12160
        assert page.imagelength == 173
12161
        assert page.bitspersample == 16
12162
        assert page.is_contiguous
12163
        # assert series properties
12164
        series = tif.series[0]
12165
        assert series.kind == 'generic'  # imagej series failed
12166
        assert series.dataoffset == 8  # 8
12167
        assert series.shape == (173, 173)
12168
        assert series.dtype == numpy.uint16
12169
        assert series.axes == 'YX'
12170
        # assert ImageJ tags
12171
        ijmeta = tif.imagej_metadata
12172
        assert ijmeta is not None
12173
        assert ijmeta['ImageJ'] == '1.49i'
12174
        assert ijmeta['images'] == 3500
12175
        # assert data
12176
        data = tif.asarray(out='memmap')
12177
        assert isinstance(data, numpy.memmap)
12178
        assert data.shape == (173, 173)
12179
        assert data.dtype == numpy.dtype('>u2')
12180
        assert data[94, 34] == 1257
12181
        assert_aszarr_method(series, data)
12182
        assert_aszarr_method(series, data, chunkmode='page')
12183
        assert__str__(tif)
12184
        del data
12185

12186

12187
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
12188
def test_read_imagej_invalid_hyperstack():
12189
    """Test read bad ImageJ hyperstack."""
12190
    # file claims to be a hyperstack but is not stored as such
12191
    # produced by OME writer
12192
    # reported by Taras Golota on 10/27/2016
12193
    fname = private_file('imagej/X0.ome.CTZ.perm.tif')
12194
    with TiffFile(fname) as tif:
12195
        assert tif.is_imagej
12196
        assert tif.byteorder == '<'
12197
        assert len(tif.pages) == 48  # not a hyperstack
12198
        assert len(tif.series) == 1
12199
        # assert page properties
12200
        page = tif.pages.first
12201
        assert page.photometric != PHOTOMETRIC.RGB
12202
        assert page.imagewidth == 1392
12203
        assert page.imagelength == 1040
12204
        assert page.bitspersample == 16
12205
        assert page.is_contiguous
12206
        # assert series properties
12207
        series = tif.series[0]
12208
        assert series.kind == 'imagej'
12209
        assert series.dataoffset is None  # not contiguous
12210
        assert series.shape == (2, 4, 6, 1040, 1392)
12211
        assert series.dtype == numpy.uint16
12212
        assert series.axes == 'TZCYX'
12213
        # assert ImageJ tags
12214
        ijmeta = tif.imagej_metadata
12215
        assert ijmeta is not None
12216
        assert ijmeta['hyperstack']
12217
        assert ijmeta['images'] == 48
12218
        assert__str__(tif)
12219

12220

12221
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
12222
def test_read_scifio():
12223
    """Test read SCIFIO file using ImageJ metadata."""
12224
    # https://github.com/AllenCellModeling/aicsimageio/issues/436
12225
    # read
12226
    fname = private_file('scifio/2MF1P2_glia.tif')
12227
    with TiffFile(fname) as tif:
12228
        assert tif.is_imagej
12229
        assert tif.byteorder == '>'
12230
        assert len(tif.pages) == 343  # not a hyperstack
12231
        assert len(tif.series) == 1
12232
        # assert page properties
12233
        page = tif.pages.first
12234
        assert page.photometric == PHOTOMETRIC.MINISBLACK
12235
        assert page.imagewidth == 1024
12236
        assert page.imagelength == 1024
12237
        assert page.bitspersample == 8
12238
        assert page.is_contiguous
12239
        # assert series properties
12240
        series = tif.series[0]
12241
        assert series.kind == 'imagej'
12242
        assert series.dataoffset is None  # not contiguous
12243
        assert series.shape == (343, 1024, 1024)
12244
        assert series.dtype == numpy.uint8
12245
        assert series.axes == 'IYX'
12246
        assert isinstance(series.pages[2], TiffFrame)
12247
        # assert ImageJ tags
12248
        ijmeta = tif.imagej_metadata
12249
        assert ijmeta is not None
12250
        assert ijmeta['SCIFIO'] == '0.42.0'
12251
        assert ijmeta['hyperstack']
12252
        assert ijmeta['images'] == 343
12253
        # assert data
12254
        # data = series.asarray()
12255
        # assert data[192, 740, 420] == 2
12256
        # assert_aszarr_method(series, data)
12257
        assert__str__(tif)
12258

12259

12260
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
12261
def test_read_fluoview_lsp1_v_laser():
12262
    """Test read FluoView CTYX."""
12263
    # raises 'UnicodeWarning: Unicode equal comparison failed' on Python 2
12264
    fname = private_file('fluoview/lsp1-V-laser0.3-1.tif')
12265
    with TiffFile(fname) as tif:
12266
        assert tif.byteorder == '<'
12267
        assert len(tif.pages) == 100
12268
        assert len(tif.series) == 1
12269
        assert tif.is_fluoview
12270
        # assert page properties
12271
        page = tif.pages.first
12272
        assert page.is_fluoview
12273
        assert page.is_contiguous
12274
        assert page.compression == COMPRESSION.NONE
12275
        assert page.imagewidth == 256
12276
        assert page.imagelength == 256
12277
        assert page.bitspersample == 16
12278
        assert page.samplesperpixel == 1
12279
        # assert metadata
12280
        m = fluoview_description_metadata(page.description)
12281
        assert m['Version Info']['FLUOVIEW Version'] == (
12282
            'FV10-ASW ,ValidBitColunt=12'
12283
        )
12284
        assert tuple(m['LUT Ch1'][255]) == (255, 255, 255)
12285
        mm = tif.fluoview_metadata
12286
        assert mm['ImageName'] == 'lsp1-V-laser0.3-1.oib'
12287
        # assert series properties
12288
        series = tif.series[0]
12289
        assert series.shape == (2, 50, 256, 256)
12290
        assert series.dtype == numpy.uint16
12291
        assert series.axes == 'CTYX'
12292
        # assert data
12293
        data = tif.asarray()
12294
        assert data.shape == (2, 50, 256, 256)
12295
        assert data.dtype == numpy.uint16
12296
        assert round(abs(data[1, 36, 128, 128] - 824), 7) == 0
12297
        assert_aszarr_method(series, data)
12298
        assert_aszarr_method(series, data, chunkmode='page')
12299
        assert__str__(tif)
12300

12301

12302
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_LARGE, reason=REASON)
12303
def test_read_fluoview_120816_bf_f0000():
12304
    """Test read FluoView TZYX."""
12305
    fname = private_file('fluoview/120816_bf_f0000.tif')
12306
    with TiffFile(fname) as tif:
12307
        assert tif.byteorder == '<'
12308
        assert len(tif.pages) == 864
12309
        assert len(tif.series) == 1
12310
        assert tif.is_fluoview
12311
        # assert page properties
12312
        page = tif.pages.first
12313
        assert page.is_fluoview
12314
        assert page.is_contiguous
12315
        assert page.compression == COMPRESSION.NONE
12316
        assert page.imagewidth == 1024
12317
        assert page.imagelength == 1024
12318
        assert page.bitspersample == 16
12319
        assert page.samplesperpixel == 1
12320
        # assert metadata
12321
        m = fluoview_description_metadata(page.description)
12322
        assert m['Environment']['User'] == 'admin'
12323
        assert m['Region Info (Fields) Field']['Width'] == 1331.2
12324
        m = tif.fluoview_metadata
12325
        assert m['ImageName'] == '120816_bf'
12326
        # assert series properties
12327
        series = tif.series[0]
12328
        assert series.shape == (144, 6, 1024, 1024)
12329
        assert series.dtype == numpy.uint16
12330
        assert series.axes == 'TZYX'
12331
        # assert data
12332
        data = tif.asarray()
12333
        assert data.shape == (144, 6, 1024, 1024)
12334
        assert data.dtype == numpy.uint16
12335
        assert round(abs(data[1, 2, 128, 128] - 8317), 7) == 0
12336
        # too slow: assert_aszarr_method(series, data)
12337
        assert__str__(tif)
12338

12339

12340
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
12341
def test_read_metaseries():
12342
    """Test read MetaSeries 1040x1392 uint16, LZW."""
12343
    # Strips do not contain an EOI code as required by the TIFF spec.
12344
    fname = private_file('metaseries/metaseries.tif')
12345
    with TiffFile(fname) as tif:
12346
        assert tif.byteorder == '<'
12347
        assert len(tif.pages) == 1
12348
        assert len(tif.series) == 1
12349
        # assert page properties
12350
        page = tif.pages.first
12351
        assert page.imagewidth == 1392
12352
        assert page.imagelength == 1040
12353
        assert page.bitspersample == 16
12354
        # assert metadata
12355
        assert page.description.startswith('<MetaData>')
12356
        # assert series properties
12357
        series = tif.series[0]
12358
        assert series.shape == (1040, 1392)
12359
        assert series.dtype == numpy.uint16
12360
        assert series.axes == 'YX'
12361
        assert series.kind == 'uniform'
12362
        # assert data
12363
        data = tif.asarray()
12364
        assert data.shape == (1040, 1392)
12365
        assert data.dtype == numpy.uint16
12366
        assert data[256, 256] == 1917
12367
        assert_aszarr_method(series, data)
12368
        assert_aszarr_method(series, data, chunkmode='page')
12369
        assert__str__(tif)
12370

12371

12372
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
12373
def test_read_metaseries_g4d7r():
12374
    """Test read Metamorph/Metaseries."""
12375
    # 12113x13453, uint16
12376
    import uuid
12377

12378
    fname = private_file('metaseries/g4d7r.tif')
12379
    with TiffFile(fname) as tif:
12380
        assert tif.byteorder == '<'
12381
        assert len(tif.pages) == 1
12382
        assert len(tif.series) == 1
12383
        assert tif.is_metaseries
12384
        # assert page properties
12385
        page = tif.pages.first
12386
        assert page.is_metaseries
12387
        assert page.is_contiguous
12388
        assert page.compression == COMPRESSION.NONE
12389
        assert page.imagewidth == 13453
12390
        assert page.imagelength == 12113
12391
        assert page.bitspersample == 16
12392
        assert page.samplesperpixel == 1
12393
        # assert metadata
12394
        m = metaseries_description_metadata(page.description)
12395
        assert m['ApplicationVersion'] == '7.8.6.0'
12396
        assert m['PlaneInfo']['pixel-size-x'] == 13453
12397
        assert m['SetInfo']['number-of-planes'] == 1
12398
        assert m['PlaneInfo']['modification-time-local'] == datetime.datetime(
12399
            2014, 10, 28, 16, 17, 16, 620000
12400
        )
12401
        assert m['PlaneInfo']['plane-guid'] == uuid.UUID(
12402
            '213d9ee7-b38f-4598-9601-6474bf9d0c81'
12403
        )
12404
        # assert series properties
12405
        series = tif.series[0]
12406
        assert series.shape == (12113, 13453)
12407
        assert series.dtype == numpy.uint16
12408
        assert series.axes == 'YX'
12409
        assert series.kind == 'uniform'
12410
        # assert data
12411
        data = tif.asarray(out='memmap')
12412
        assert isinstance(data, numpy.memmap)
12413
        assert data.shape == (12113, 13453)
12414
        assert data.dtype == numpy.dtype('<u2')
12415
        assert round(abs(data[512, 2856] - 4095), 7) == 0
12416
        if not SKIP_LARGE:
12417
            assert_aszarr_method(series, data)
12418
            assert_aszarr_method(series, data, chunkmode='page')
12419
        assert__str__(tif)
12420

12421

12422
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
12423
def test_read_mdgel_rat():
12424
    """Test read Molecular Dynamics GEL."""
12425
    # Second page does not contain data, only private tags
12426
    fname = private_file('mdgel/rat.gel')
12427
    with TiffFile(fname) as tif:
12428
        assert tif.byteorder == '<'
12429
        assert len(tif.pages) == 2
12430
        assert len(tif.series) == 1
12431
        # assert page properties
12432
        page = tif.pages.first
12433
        assert page.is_contiguous
12434
        assert page.compression == COMPRESSION.NONE
12435
        assert page.imagewidth == 1528
12436
        assert page.imagelength == 413
12437
        assert page.bitspersample == 16
12438
        assert page.samplesperpixel == 1
12439
        assert page.tags['Software'].value == (
12440
            'ImageQuant Software Release Version 2.0'
12441
        )
12442
        assert page.tags['PageName'].value == r'C:\DATA\RAT.GEL'
12443

12444
        # assert 2nd page properties
12445
        page = tif.pages[1]
12446
        assert page.is_mdgel
12447
        assert page.imagewidth == 0
12448
        assert page.imagelength == 0
12449
        assert page.bitspersample == 1
12450
        assert page.samplesperpixel == 1
12451
        assert page.tags['MDFileTag'].value == 2
12452
        assert page.tags['MDScalePixel'].value == (1, 21025)
12453
        assert len(page.tags['MDColorTable'].value) == 17
12454
        md = tif.mdgel_metadata
12455
        assert md['SampleInfo'] == 'Rat slices from Dr. Schweitzer'
12456
        assert md['PrepDate'] == '12 July 90'
12457
        assert md['PrepTime'] == '40hr'
12458
        assert md['FileUnits'] == 'Counts'
12459

12460
        # assert series properties
12461
        series = tif.series[0]
12462
        assert series.shape == (413, 1528)
12463
        assert series.dtype == numpy.float32
12464
        assert series.axes == 'YX'
12465
        assert series.kind == 'mdgel'
12466
        # assert data
12467
        data = series.asarray()
12468
        assert isinstance(data, numpy.ndarray)
12469
        assert data.shape == (413, 1528)
12470
        assert data.dtype == numpy.float32
12471
        assert round(abs(data[260, 740] - 399.1728515625), 7) == 0
12472
        assert_aszarr_method(series, data)
12473
        assert_aszarr_method(series, data, chunkmode='page')
12474
        assert__str__(tif)
12475

12476

12477
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
12478
def test_read_mediacy_imagepro():
12479
    """Test read Media Cybernetics SEQ."""
12480
    # TZYX, uint16, OME multifile TIFF
12481
    fname = private_file('mediacy/imagepro.tif')
12482
    with TiffFile(fname) as tif:
12483
        assert tif.byteorder == '<'
12484
        assert len(tif.pages) == 1
12485
        assert len(tif.series) == 1
12486
        # assert page properties
12487
        page = tif.pages.first
12488
        assert page.is_mediacy
12489
        assert page.is_contiguous
12490
        assert page.compression == COMPRESSION.NONE
12491
        assert page.imagewidth == 201
12492
        assert page.imagelength == 201
12493
        assert page.bitspersample == 8
12494
        assert page.samplesperpixel == 1
12495
        assert page.tags['Software'].value == 'Image-Pro Plus'
12496
        assert page.tags['MC_Id'].value[:-1] == b'MC TIFF 4.0'
12497
        # assert series properties
12498
        series = tif.series[0]
12499
        assert series.shape == (201, 201)
12500
        assert series.dtype == numpy.uint8
12501
        assert series.axes == 'YX'
12502
        assert series.kind == 'uniform'
12503
        # assert data
12504
        data = tif.asarray()
12505
        assert data.shape == (201, 201)
12506
        assert data.dtype == numpy.uint8
12507
        assert round(abs(data[120, 34] - 4), 7) == 0
12508
        assert_aszarr_method(series, data)
12509
        assert_aszarr_method(series, data, chunkmode='page')
12510
        assert__str__(tif)
12511

12512

12513
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
12514
def test_read_pilatus_100k():
12515
    """Test read Pilatus."""
12516
    fname = private_file('TvxPilatus/Pilatus100K_scan030_033.tiff')
12517
    with TiffFile(fname) as tif:
12518
        assert tif.byteorder == '<'
12519
        assert len(tif.pages) == 1
12520
        assert tif.is_pilatus
12521
        # assert page properties
12522
        page = tif.pages.first
12523
        assert page.imagewidth == 487
12524
        assert page.imagelength == 195
12525
        assert page.bitspersample == 32
12526
        assert page.samplesperpixel == 1
12527
        # assert metadata
12528
        assert page.tags['Model'].value == (
12529
            'PILATUS 100K, S/N 1-0230, Cornell University'
12530
        )
12531
        attr = pilatus_description_metadata(page.description)
12532
        assert attr['Tau'] == 1.991e-07
12533
        assert attr['Silicon'] == 0.000320
12534
        assert_aszarr_method(page)
12535
        assert_aszarr_method(page, chunkmode='page')
12536
        assert__str__(tif)
12537

12538

12539
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
12540
def test_read_pilatus_gibuf2():
12541
    """Test read Pilatus."""
12542
    fname = private_file('TvxPilatus/GIbuf2_A9_18_001_0009.tiff')
12543
    with TiffFile(fname) as tif:
12544
        assert tif.byteorder == '<'
12545
        assert len(tif.pages) == 1
12546
        assert tif.is_pilatus
12547
        # assert page properties
12548
        page = tif.pages.first
12549
        assert page.imagewidth == 487
12550
        assert page.imagelength == 195
12551
        assert page.bitspersample == 32
12552
        assert page.samplesperpixel == 1
12553
        # assert metadata
12554
        assert page.tags['Model'].value == 'PILATUS 100K-S, S/N 1-0299,'
12555
        attr = pilatus_description_metadata(page.description)
12556
        assert attr['Filter_transmission'] == 1.0
12557
        assert attr['Silicon'] == 0.000320
12558
        assert_aszarr_method(page)
12559
        assert__str__(tif)
12560

12561

12562
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
12563
def test_read_epics_attrib():
12564
    """Test read EPICS."""
12565
    fname = private_file('epics/attrib.tif')
12566
    with TiffFile(fname) as tif:
12567
        assert tif.is_epics
12568
        assert tif.byteorder == '<'
12569
        assert len(tif.pages) == 1
12570
        assert len(tif.series) == 1
12571
        # assert series properties
12572
        series = tif.series[0]
12573
        assert series.shape == (2048, 2048)
12574
        assert series.dtype == numpy.uint16
12575
        assert series.axes == 'YX'
12576
        assert series.kind == 'uniform'
12577
        # assert page properties
12578
        page = tif.pages.first
12579
        assert page.shape == (2048, 2048)
12580
        assert page.imagewidth == 2048
12581
        assert page.imagelength == 2048
12582
        assert page.bitspersample == 16
12583
        assert page.is_contiguous
12584
        # assert EPICS tags
12585
        tags = tif.epics_metadata
12586
        assert tags['timeStamp'] == 802117891.5714135
12587
        assert tags['uniqueID'] == 15
12588
        assert tags['Focus'] == 0.6778
12589
        assert epics_datetime(
12590
            tags['epicsTSSec'], tags['epicsTSNsec']
12591
        ) == datetime.datetime(2015, 6, 2, 11, 31, 56, 103746)
12592
        assert_aszarr_method(page)
12593
        assert_aszarr_method(page, chunkmode='page')
12594
        assert__str__(tif)
12595

12596

12597
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
12598
def test_read_tvips_tietz_16bit():
12599
    """Test read TVIPS metadata."""
12600
    # file provided by Marco Oster on 10/26/2016
12601
    fname = private_file('tvips/test_tietz_16bit.tif')
12602
    with TiffFile(fname) as tif:
12603
        assert tif.is_tvips
12604
        tvips = tif.tvips_metadata
12605
        assert tvips['Magic'] == 0xAAAAAAAA
12606
        assert tvips['ImageFolder'] == 'B:\\4Marco\\Images\\Tiling_EMTOOLS\\'
12607
        assert_aszarr_method(tif)
12608
        assert__str__(tif)
12609

12610

12611
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
12612
def test_read_gdal_structural_metadata():
12613
    """Test read non-TIFF GDAL structural metadata."""
12614
    fname = private_file('CloudOptimizedGeoTIFF/cog_rgb.tif')
12615
    with TiffFile(fname) as tif:
12616
        assert not tif.is_geotiff
12617
        assert tif.byteorder == '<'
12618
        assert len(tif.pages) == 2
12619
        assert len(tif.series) == 1
12620
        series = tif.series[0]
12621
        assert series.shape == (256, 256, 3)
12622
        assert series.dtype == numpy.uint8
12623
        assert series.axes == 'YXS'
12624
        assert series.kind == 'generic'
12625
        assert tif.gdal_structural_metadata == {
12626
            'LAYOUT': 'IFDS_BEFORE_DATA',
12627
            'BLOCK_ORDER': 'ROW_MAJOR',
12628
            'BLOCK_LEADER': 'SIZE_AS_UINT4',
12629
            'BLOCK_TRAILER': 'LAST_4_BYTES_REPEATED',
12630
            'KNOWN_INCOMPATIBLE_EDITION': 'NO',
12631
        }
12632

12633

12634
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
12635
def test_read_geotiff_dimapdocument():
12636
    """Test read GeoTIFF with 43 MB XML tag value."""
12637
    # tag 65000  45070067s @487  "<Dimap_Document...
12638
    fname = private_file('geotiff/DimapDocument.tif')
12639
    with TiffFile(fname) as tif:
12640
        assert tif.is_geotiff
12641
        assert tif.byteorder == '>'
12642
        assert len(tif.pages) == 1
12643
        assert len(tif.series) == 1
12644
        # assert series properties
12645
        series = tif.series[0]
12646
        assert series.shape == (1830, 1830)
12647
        assert series.dtype == numpy.uint16
12648
        assert series.axes == 'YX'
12649
        assert series.kind == 'uniform'
12650
        # assert page properties
12651
        page = tif.pages.first
12652
        assert page.shape == (1830, 1830)
12653
        assert page.imagewidth == 1830
12654
        assert page.imagelength == 1830
12655
        assert page.bitspersample == 16
12656
        assert page.is_contiguous
12657
        assert page.tags['65000'].value.startswith(
12658
            '<?xml version="1.0" encoding="ISO-8859-1"?>'
12659
        )
12660
        # assert GeoTIFF tags
12661
        tags = tif.geotiff_metadata
12662
        assert tags['GTCitationGeoKey'] == 'WGS 84 / UTM zone 29N'
12663
        assert tags['ProjectedCSTypeGeoKey'] == 32629
12664
        assert_array_almost_equal(
12665
            tags['ModelTransformation'],
12666
            [
12667
                [60.0, 0.0, 0.0, 6.0e5],
12668
                [0.0, -60.0, 0.0, 5900040.0],
12669
                [0.0, 0.0, 0.0, 0.0],
12670
                [0.0, 0.0, 0.0, 1.0],
12671
            ],
12672
        )
12673
        assert_aszarr_method(page)
12674
        assert__str__(tif)
12675

12676

12677
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
12678
def test_read_geotiff_spaf27_markedcorrect():
12679
    """Test read GeoTIFF."""
12680
    fname = private_file('geotiff/spaf27_markedcorrect.tif')
12681
    with TiffFile(fname) as tif:
12682
        assert tif.is_geotiff
12683
        assert tif.byteorder == '<'
12684
        assert len(tif.pages) == 1
12685
        assert len(tif.series) == 1
12686
        # assert series properties
12687
        series = tif.series[0]
12688
        assert series.shape == (20, 20)
12689
        assert series.dtype == numpy.uint8
12690
        assert series.axes == 'YX'
12691
        assert series.kind == 'uniform'
12692
        # assert page properties
12693
        page = tif.pages.first
12694
        assert page.shape == (20, 20)
12695
        assert page.imagewidth == 20
12696
        assert page.imagelength == 20
12697
        assert page.bitspersample == 8
12698
        assert page.is_contiguous
12699
        # assert GeoTIFF tags
12700
        tags = tif.geotiff_metadata
12701
        assert tags['GTCitationGeoKey'] == 'NAD27 / California zone VI'
12702
        assert tags['GeogAngularUnitsGeoKey'] == 9102
12703
        assert tags['ProjFalseOriginLatGeoKey'] == 32.1666666666667
12704
        assert_array_almost_equal(
12705
            tags['ModelPixelScale'], [195.509321, 198.32184, 0]
12706
        )
12707
        assert_aszarr_method(page)
12708
        assert__str__(tif)
12709

12710

12711
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
12712
def test_read_geotiff_cint16():
12713
    """Test read complex integer images."""
12714
    fname = private_file('geotiff/cint16.tif')
12715
    with TiffFile(fname) as tif:
12716
        assert tif.is_geotiff
12717
        assert tif.byteorder == '<'
12718
        assert len(tif.pages) == 1
12719
        assert len(tif.series) == 1
12720
        # assert page properties
12721
        page = tif.pages.first
12722
        assert page.sampleformat == SAMPLEFORMAT.COMPLEXINT
12723
        assert page.bitspersample == 32
12724
        assert page.dtype == numpy.complex64
12725
        assert page.shape == (100, 100)
12726
        assert page.imagewidth == 100
12727
        assert page.imagelength == 100
12728
        assert page.compression == COMPRESSION.ADOBE_DEFLATE
12729
        assert not page.is_contiguous
12730
        data = page.asarray()
12731
        data[9, 11] == 0 + 0j
12732
        assert_aszarr_method(page, data)
12733
        assert__str__(tif)
12734

12735

12736
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
12737
@pytest.mark.parametrize('bits', [16, 32])
12738
def test_read_complexint(bits):
12739
    """Test read complex integer images."""
12740
    fname = private_file(f'gdal/cint{bits}.tif')
12741
    with TiffFile(fname) as tif:
12742
        assert tif.is_geotiff
12743
        assert tif.byteorder == '<'
12744
        assert len(tif.pages) == 1
12745
        assert len(tif.series) == 1
12746
        # assert page properties
12747
        page = tif.pages.first
12748
        assert page.sampleformat == SAMPLEFORMAT.COMPLEXINT
12749
        assert page.bitspersample == bits * 2
12750
        assert page.dtype == f'complex{bits * 4}'
12751
        assert page.shape == (20, 20)
12752
        assert page.imagewidth == 20
12753
        assert page.imagelength == 20
12754
        assert not page.is_contiguous
12755
        data = page.asarray()
12756
        data[9, 11] == 107 + 0j
12757
        # assert GeoTIFF tags
12758
        tags = tif.geotiff_metadata
12759
        assert tags['GTCitationGeoKey'] == 'NAD27 / UTM zone 11N'
12760
        assert_aszarr_method(page, data)
12761
        assert__str__(tif)
12762

12763

12764
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
12765
def test_read_qpi():
12766
    """Test read PerkinElmer-QPI, non Pyramid."""
12767
    fname = private_file('PerkinElmer-QPI/18-2470_2471_Scan1.qptiff')
12768
    with TiffFile(fname) as tif:
12769
        assert len(tif.series) == 4
12770
        assert len(tif.pages) == 9
12771
        assert tif.is_qpi
12772
        page = tif.pages.first
12773
        assert page.compression == COMPRESSION.JPEG
12774
        assert page.photometric == PHOTOMETRIC.RGB
12775
        assert page.planarconfig == PLANARCONFIG.CONTIG
12776
        assert page.imagewidth == 34560
12777
        assert page.imagelength == 57600
12778
        assert page.bitspersample == 8
12779
        assert page.samplesperpixel == 3
12780
        assert page.tags['Software'].value == 'PerkinElmer-QPI'
12781

12782
        page = tif.pages[1]
12783
        assert page.compression == COMPRESSION.LZW
12784
        assert page.photometric == PHOTOMETRIC.RGB
12785
        assert page.planarconfig == PLANARCONFIG.CONTIG
12786
        assert page.imagewidth == 270
12787
        assert page.imagelength == 450
12788
        assert page.bitspersample == 8
12789
        assert page.samplesperpixel == 3
12790

12791
        series = tif.series[0]
12792
        assert series.kind == 'qpi'
12793
        assert series.name == 'Baseline'
12794
        assert series.shape == (57600, 34560, 3)
12795
        assert series.dtype == numpy.uint8
12796
        assert series.is_pyramidal
12797
        assert len(series.levels) == 6
12798

12799
        series = tif.series[1]
12800
        assert series.kind == 'qpi'
12801
        assert series.name == 'Thumbnail'
12802
        assert series.shape == (450, 270, 3)
12803
        assert series.dtype == numpy.uint8
12804
        assert not series.is_pyramidal
12805

12806
        series = tif.series[2]
12807
        assert series.kind == 'qpi'
12808
        assert series.name == 'Macro'
12809
        assert series.shape == (4065, 2105, 3)
12810
        assert series.dtype == numpy.uint8
12811
        assert not series.is_pyramidal
12812

12813
        series = tif.series[3]
12814
        assert series.kind == 'qpi'
12815
        assert series.name == 'Label'
12816
        assert series.shape == (453, 526, 3)
12817
        assert series.dtype == numpy.uint8
12818
        assert not series.is_pyramidal
12819

12820
        # assert data
12821
        image = tif.asarray(series=1)
12822
        image = tif.asarray(series=2)
12823
        image = tif.asarray(series=3)
12824
        image = tif.asarray(series=0, level=4)
12825
        assert image.shape == (3600, 2160, 3)
12826
        assert image.dtype == numpy.uint8
12827
        assert tuple(image[1200, 1500]) == (244, 233, 229)
12828
        assert_aszarr_method(tif, image, series=0, level=4)
12829
        assert__str__(tif)
12830

12831

12832
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
12833
def test_read_qpi_nopyramid():
12834
    """Test read PerkinElmer-QPI, non Pyramid."""
12835
    fname = private_file(
12836
        'PerkinElmer-QPI/LuCa-7color_[13860,52919]_1x1component_data.tiff'
12837
    )
12838
    with TiffFile(fname) as tif:
12839
        assert len(tif.series) == 2
12840
        assert len(tif.pages) == 9
12841
        assert tif.is_qpi
12842
        page = tif.pages.first
12843
        assert page.compression == COMPRESSION.LZW
12844
        assert page.photometric == PHOTOMETRIC.MINISBLACK
12845
        assert page.planarconfig == PLANARCONFIG.CONTIG
12846
        assert page.imagewidth == 1868
12847
        assert page.imagelength == 1400
12848
        assert page.bitspersample == 32
12849
        assert page.samplesperpixel == 1
12850
        assert page.tags['Software'].value == 'PerkinElmer-QPI'
12851
        series = tif.series[0]
12852
        assert series.kind == 'qpi'
12853
        assert series.shape == (8, 1400, 1868)
12854
        assert series.dtype == numpy.float32
12855
        assert not series.is_pyramidal
12856
        series = tif.series[1]
12857
        assert series.kind == 'qpi'
12858
        assert series.shape == (350, 467, 3)
12859
        assert series.dtype == numpy.uint8
12860
        assert not series.is_pyramidal
12861
        # assert data
12862
        image = tif.asarray()
12863
        assert image.shape == (8, 1400, 1868)
12864
        assert image.dtype == numpy.float32
12865
        assert image[7, 1200, 1500] == 2.2132580280303955
12866
        image = tif.asarray(series=1)
12867
        assert image.shape == (350, 467, 3)
12868
        assert image.dtype == numpy.uint8
12869
        assert image[300, 400, 1] == 48
12870
        assert_aszarr_method(tif, image, series=1)
12871
        assert_aszarr_method(tif, image, series=1, chunkmode='page')
12872
        assert__str__(tif)
12873

12874

12875
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
12876
def test_read_indica():
12877
    """Test read Indica Labs pyramid."""
12878
    # https://forum.image.sc/t/89191/4
12879
    fname = private_file('Indica/mouse_link.tif')
12880
    with TiffFile(fname) as tif:
12881
        assert len(tif.series) == 1
12882
        assert len(tif.pages) == 40
12883
        assert tif.is_indica
12884
        assert tif.indica_metadata.endswith('</indica>')
12885
        page = tif.pages.first
12886
        assert page.compression == COMPRESSION.ADOBE_DEFLATE
12887
        assert page.photometric == PHOTOMETRIC.MINISBLACK
12888
        assert page.shape == (26836, 18282)
12889
        assert page.bitspersample == 32
12890
        assert page.samplesperpixel == 1
12891
        assert page.dtype == numpy.float32
12892
        assert page.tags['Software'].value == 'IndicaLabsImageWriter v1.2.1'
12893
        series = tif.series[0]
12894
        assert series.kind == 'generic'  # 'indica'
12895
        assert series.axes == 'IYX'  # 'CYX'
12896
        assert series.shape == (8, 26836, 18282)
12897
        assert series.dtype == numpy.float32
12898
        assert len(series.levels) == 5
12899
        assert series.is_pyramidal
12900
        # assert data
12901
        image = tif.asarray(series=0, level=3)
12902
        assert image.shape == (8, 3355, 2286)
12903
        assert image.dtype == numpy.float32
12904
        assert_array_almost_equal(image[7, 3000, 1000], 6.0852714)
12905
        assert_aszarr_method(series, image, level=3)
12906
        assert_aszarr_method(series, image, level=3, chunkmode='page')
12907
        assert__str__(tif)
12908

12909

12910
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
12911
def test_read_avs():
12912
    """Test read Argos AVS pyramid."""
12913
    # https://github.com/openslide/openslide/issues/614
12914
    fname = private_file('ArgosAVS/TestSlide1_ZStack.avs')
12915
    with TiffFile(fname) as tif:
12916
        assert len(tif.series) == 3
12917
        assert len(tif.pages) == 42
12918
        assert tif.is_avs
12919
        assert tif.avs_metadata.startswith('<Argos.Scan.Metadata>')
12920
        page = tif.pages.first
12921
        assert page.compression == COMPRESSION.JPEG
12922
        assert page.photometric == PHOTOMETRIC.YCBCR
12923
        assert page.shape == (57440, 130546, 3)
12924
        assert page.bitspersample == 8
12925
        assert page.samplesperpixel == 3
12926
        assert page.dtype == numpy.uint8
12927
        series = tif.series[0]
12928
        assert series.kind == 'avs'
12929
        assert series.name == 'Baseline'
12930
        assert series.axes == 'ZYXS'
12931
        assert series.shape == (5, 57440, 130546, 3)
12932
        assert series.dtype == numpy.uint8
12933
        assert series.is_pyramidal
12934
        assert len(series.levels) == 8
12935
        series = tif.series[1]
12936
        assert series.kind == 'avs'
12937
        assert series.name == 'Map'
12938
        assert series.axes == 'YXS'
12939
        assert series.shape == (1399, 3180, 3)
12940
        series = tif.series[2]
12941
        assert series.kind == 'avs'
12942
        assert series.name == 'Macro'
12943
        assert series.axes == 'YXS'
12944
        assert series.shape == (508, 1489, 3)
12945
        # assert data
12946
        series = tif.series[0]
12947
        image = tif.asarray(series=0, level=4)
12948
        assert image.shape == (5, 3590, 8159, 3)
12949
        assert image.dtype == numpy.uint8
12950
        assert image[2, 900, 3000, 0] == 218
12951
        assert_aszarr_method(series, image, level=4)
12952
        assert_aszarr_method(series, image, level=4, chunkmode='page')
12953
        assert__str__(tif)
12954

12955

12956
@pytest.mark.skipif(
12957
    SKIP_PRIVATE or SKIP_CODECS or not imagecodecs.JPEG.available,
12958
    reason=REASON,
12959
)
12960
def test_read_philips():
12961
    """Test read Philips DP pyramid."""
12962
    # https://camelyon17.grand-challenge.org/Data/
12963
    fname = private_file('PhilipsDP/test_001.tif')
12964
    with TiffFile(fname) as tif:
12965
        assert len(tif.series) == 1
12966
        assert len(tif.pages) == 9
12967
        assert tif.is_philips
12968
        assert tif.philips_metadata.endswith('</DataObject>')
12969

12970
        page = tif.pages.first
12971
        assert page.compression == COMPRESSION.JPEG
12972
        assert page.photometric == PHOTOMETRIC.YCBCR
12973
        assert page.planarconfig == PLANARCONFIG.CONTIG
12974
        assert page.tags['ImageWidth'].value == 86016
12975
        assert page.tags['ImageLength'].value == 89600
12976
        assert page.imagewidth == 86016
12977
        assert page.imagelength == 89600
12978
        assert page.bitspersample == 8
12979
        assert page.samplesperpixel == 3
12980
        assert page.tags['Software'].value == 'Philips DP v1.0'
12981

12982
        series = tif.series[0]
12983
        assert series.kind == 'philips'
12984
        assert series.shape == (89600, 86016, 3)
12985
        assert len(series.levels) == 9
12986
        assert series.is_pyramidal
12987
        assert series.levels[1].shape == (44800, 43008, 3)
12988
        assert series.levels[2].shape == (22400, 21504, 3)
12989
        assert series.levels[3].shape == (11200, 10752, 3)
12990
        assert series.levels[4].shape == (5600, 5376, 3)
12991
        assert series.levels[5].shape == (2800, 2688, 3)
12992
        assert series.levels[6].shape == (1400, 1344, 3)
12993
        assert series.levels[7].shape == (700, 672, 3)
12994
        assert series.levels[8].shape == (350, 336, 3)
12995

12996
        page = series.levels[1].keyframe
12997
        assert page.compression == COMPRESSION.JPEG
12998
        assert page.photometric == PHOTOMETRIC.YCBCR
12999
        assert page.planarconfig == PLANARCONFIG.CONTIG
13000
        assert page.tags['ImageWidth'].value == 43008
13001
        assert page.tags['ImageLength'].value == 45056
13002
        assert page.imagewidth == 43008
13003
        assert page.imagelength == 44800
13004

13005
        for level in range(1, 9):
13006
            tif.asarray(series=0, level=level)
13007

13008
        # assert data
13009
        image = tif.asarray(series=0, level=5)
13010
        assert image.shape == (2800, 2688, 3)
13011
        assert image[300, 400, 1] == 206
13012
        assert_aszarr_method(series, image, level=5)
13013
        assert_aszarr_method(series, image, level=5, chunkmode='page')
13014
        assert__str__(tif)
13015

13016

13017
@pytest.mark.skipif(
13018
    SKIP_PRIVATE or SKIP_CODECS or not imagecodecs.JPEG.available,
13019
    reason=REASON,
13020
)
13021
def test_read_philips_issue249():
13022
    """Test write_fsspec with Philips slide missing row of tiles."""
13023
    # https://github.com/cgohlke/tifffile/issues/249
13024
    fname = private_file('PhilipsDP/patient_080_node_2.tif')
13025
    with TiffFile(fname) as tif:
13026
        assert len(tif.series) == 2
13027
        assert len(tif.pages) == 11
13028
        assert tif.is_philips
13029
        assert tif.philips_metadata.endswith('</DataObject>')
13030

13031
        page = tif.pages.first
13032
        assert page.compression == COMPRESSION.JPEG
13033
        assert page.photometric == PHOTOMETRIC.YCBCR
13034
        assert page.planarconfig == PLANARCONFIG.CONTIG
13035
        assert page.tags['ImageWidth'].value == 155136
13036
        assert page.tags['ImageLength'].value == 78336
13037
        assert page.imagewidth == 155136
13038
        assert page.imagelength == 78336
13039
        assert page.bitspersample == 8
13040
        assert page.samplesperpixel == 3
13041
        assert page.tags['Software'].value == 'Philips DP v1.0'
13042

13043
        series = tif.series[1]
13044
        assert series.kind == 'philips'
13045
        assert series.name == 'Macro'
13046
        assert series.shape == (801, 1756, 3)
13047
        assert len(series.levels) == 1
13048
        assert not series.is_pyramidal
13049

13050
        series = tif.series[0]
13051
        assert series.kind == 'philips'
13052
        assert series.name == 'Baseline'
13053
        assert series.shape == (78336, 155136, 3)
13054
        assert len(series.levels) == 10
13055
        assert series.is_pyramidal
13056

13057
        page = series.levels[3].keyframe
13058
        assert page.compression == COMPRESSION.JPEG
13059
        assert page.photometric == PHOTOMETRIC.YCBCR
13060
        assert page.planarconfig == PLANARCONFIG.CONTIG
13061
        assert page.tags['ImageWidth'].value == 19456
13062
        assert page.tags['ImageLength'].value == 9728
13063
        assert page.imagewidth == 19392
13064
        assert page.imagelength == 9792
13065

13066
        for level in range(1, 10):
13067
            tif.asarray(series=0, level=level)
13068

13069
        # assert data
13070
        image = tif.asarray(series=0, level=3)
13071
        assert image.shape == (9792, 19392, 3)
13072
        assert image[300, 400, 1] == 226
13073
        assert image[9791, 0, 1] == 0
13074
        assert_aszarr_method(series, image, level=3)
13075
        assert__str__(tif)
13076

13077
        if SKIP_ZARR:
13078
            return
13079

13080
        # write fsspec
13081
        from imagecodecs.numcodecs import register_codecs
13082

13083
        register_codecs('imagecodecs_jpeg', verbose=False)
13084
        url = os.path.dirname(fname).replace('\\', '/')
13085
        with TempFileName('issue_philips_fsspec', ext='.json') as jsonfile:
13086
            page.aszarr().write_fsspec(jsonfile, url, version=0)
13087
            mapper = fsspec.get_mapper(
13088
                'reference://',
13089
                fo=jsonfile,
13090
                target_protocol='file',
13091
                remote_protocol='file',
13092
            )
13093
            zobj = zarr.open(mapper, mode='r')
13094
            assert_array_equal(zobj[:], image)
13095

13096

13097
@pytest.mark.skipif(
13098
    SKIP_PRIVATE or SKIP_CODECS or not imagecodecs.JPEG.available,
13099
    reason=REASON,
13100
)
13101
def test_read_philips_issue253():
13102
    """Test read Philips DP pyramid with seemingly extra column of tiles."""
13103
    # https://github.com/cgohlke/tifffile/issues/253
13104
    # https://registry.opendata.aws/camelyon/
13105
    fname = private_file('PhilipsDP/sample.tiff')
13106
    with TiffFile(fname) as tif:
13107
        assert len(tif.series) == 3
13108
        assert len(tif.pages) == 12
13109
        assert tif.is_philips
13110
        assert tif.philips_metadata.endswith('</DataObject>')
13111

13112
        page = tif.pages.first
13113
        assert page.compression == COMPRESSION.JPEG
13114
        assert page.photometric == PHOTOMETRIC.RGB
13115
        assert page.planarconfig == PLANARCONFIG.CONTIG
13116
        assert page.tags['ImageWidth'].value == 188416
13117
        assert page.tags['ImageLength'].value == 93696
13118
        assert page.imagewidth == 188416
13119
        assert page.imagelength == 93696
13120
        assert page.bitspersample == 8
13121
        assert page.samplesperpixel == 3
13122
        assert page.tags['Software'].value == 'Philips DP v1.0'
13123

13124
        series = tif.series[1]
13125
        assert series.kind == 'philips'
13126
        assert series.name == 'Macro'
13127
        assert series.shape == (812, 1806, 3)
13128
        assert not series.is_pyramidal
13129

13130
        series = tif.series[2]
13131
        assert series.kind == 'philips'
13132
        assert series.name == 'Label'
13133
        assert series.shape == (812, 671, 3)
13134
        assert not series.is_pyramidal
13135

13136
        series = tif.series[0]
13137
        assert series.kind == 'philips'
13138
        assert series.name == 'Baseline'
13139
        assert series.shape == (93696, 188416, 3)
13140
        assert len(series.levels) == 10
13141
        assert series.is_pyramidal
13142
        assert series.levels[1].shape == (46848, 94208, 3)
13143
        assert series.levels[2].shape == (23424, 47104, 3)
13144
        assert series.levels[3].shape == (11712, 23552, 3)
13145
        assert series.levels[4].shape == (5856, 11776, 3)
13146
        assert series.levels[5].shape == (2928, 5888, 3)
13147
        assert series.levels[6].shape == (1464, 2944, 3)
13148
        assert series.levels[7].shape == (732, 1472, 3)
13149
        assert series.levels[8].shape == (366, 736, 3)
13150
        assert series.levels[9].shape == (183, 368, 3)
13151

13152
        page = series.levels[1].keyframe
13153
        assert page.compression == COMPRESSION.JPEG
13154
        assert page.photometric == PHOTOMETRIC.RGB
13155
        assert page.planarconfig == PLANARCONFIG.CONTIG
13156
        assert page.tags['ImageWidth'].value == 94208
13157
        assert page.tags['ImageLength'].value == 47104
13158
        assert page.imagewidth == 94208
13159
        assert page.imagelength == 46848
13160

13161
        for level in range(1, 10):
13162
            tif.asarray(series=0, level=level)
13163

13164
        # assert data
13165
        image = tif.asarray(series=0, level=5)
13166
        assert image.shape == (2928, 5888, 3)
13167
        assert image[300, 400, 1] == 254
13168
        assert_aszarr_method(series, image, level=5)
13169
        assert_aszarr_method(series, image, level=5, chunkmode='page')
13170
        assert__str__(tif)
13171

13172

13173
@pytest.mark.skipif(
13174
    SKIP_PRIVATE or SKIP_CODECS or not imagecodecs.JPEG.available,
13175
    reason=REASON,
13176
)
13177
def test_read_zif():
13178
    """Test read Zoomable Image Format ZIF."""
13179
    fname = private_file('zif/ZoomifyImageExample.zif')
13180
    with TiffFile(fname) as tif:
13181
        # assert tif.is_zif
13182
        assert len(tif.pages) == 5
13183
        assert len(tif.series) == 1
13184
        for page in tif.pages:
13185
            assert page.description == (
13186
                'Created by Objective ' 'Pathology Services'
13187
            )
13188
        # first page
13189
        page = tif.pages.first
13190
        assert page.photometric == PHOTOMETRIC.YCBCR
13191
        assert page.compression == COMPRESSION.JPEG
13192
        assert page.shape == (3120, 2080, 3)
13193
        assert tuple(page.asarray()[3110, 2070, :]) == (27, 45, 59)
13194
        # page 4
13195
        page = tif.pages[-1]
13196
        assert page.photometric == PHOTOMETRIC.YCBCR
13197
        assert page.compression == COMPRESSION.JPEG
13198
        assert page.shape == (195, 130, 3)
13199
        assert tuple(page.asarray()[191, 127, :]) == (30, 49, 66)
13200
        # series
13201
        series = tif.series[0]
13202
        assert series.kind == 'generic'
13203
        assert series.is_pyramidal
13204
        assert len(series.levels) == 5
13205
        assert series.shape == (3120, 2080, 3)
13206
        assert tuple(series.asarray()[3110, 2070, :]) == (27, 45, 59)
13207
        assert series.levels[-1].shape == (195, 130, 3)
13208
        assert tuple(series.asarray(level=-1)[191, 127, :]) == (30, 49, 66)
13209
        assert_aszarr_method(series, level=-1)
13210
        assert__str__(tif)
13211

13212

13213
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
13214
def test_read_vsi():
13215
    """Test read Olympus VSI."""
13216
    fname = private_file('VSI/brightfield.vsi')
13217
    with TiffFile(fname) as tif:
13218
        assert not tif.is_sis
13219
        assert tif.byteorder == '<'
13220
        assert len(tif.pages) == 5
13221
        assert len(tif.series) == 5
13222
        # assert page properties
13223
        page = tif.pages.first
13224
        assert not page.is_contiguous
13225
        assert page.imagewidth == 991
13226
        assert page.imagelength == 375
13227
        assert page.bitspersample == 8
13228
        assert page.samplesperpixel == 3
13229
        assert page.tags['Artist'].value == 'ics'
13230
        # assert data
13231
        data = tif.asarray()
13232
        assert data.shape == (375, 991, 3)
13233
        assert data[200, 256, 1] == 3
13234
        # assert metadata
13235
        sis = tif.sis_metadata
13236
        assert sis['magnification'] == 1.0
13237
        assert_aszarr_method(tif, data)
13238
        assert_aszarr_method(tif, data, chunkmode='page')
13239
        assert__str__(tif)
13240

13241

13242
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
13243
def test_read_sis():
13244
    """Test read Olympus SIS."""
13245
    fname = private_file('sis/4A5IE8EM_F00000409.tif')
13246
    with TiffFile(fname) as tif:
13247
        assert tif.is_sis
13248
        assert tif.byteorder == '<'
13249
        assert len(tif.pages) == 122
13250
        assert len(tif.series) == 1
13251
        # assert page properties
13252
        page = tif.pages.first
13253
        assert page.is_contiguous
13254
        assert page.imagewidth == 353
13255
        assert page.imagelength == 310
13256
        assert page.bitspersample == 16
13257
        assert page.samplesperpixel == 1
13258
        assert page.tags['Software'].value == 'analySIS 5.0'
13259
        # assert data
13260
        data = tif.asarray()
13261
        assert data.shape == (61, 2, 310, 353)
13262
        assert data[30, 1, 256, 256] == 210
13263
        # assert metadata
13264
        sis = tif.sis_metadata
13265
        assert sis['axes'] == 'TC'
13266
        assert sis['shape'] == (61, 2)
13267
        assert sis['Band'][1]['BandName'] == 'Fura380'
13268
        assert sis['Band'][0]['LUT'].shape == (256, 3)
13269
        assert sis['Time']['TimePos'].shape == (61,)
13270
        assert sis['name'] == 'Hela-Zellen'
13271
        assert sis['magnification'] == 60.0
13272
        assert_aszarr_method(tif, data)
13273
        assert_aszarr_method(tif, data, chunkmode='page')
13274
        assert__str__(tif)
13275

13276

13277
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
13278
def test_read_sis_noini():
13279
    """Test read Olympus SIS without INI tag."""
13280
    fname = private_file('sis/110.tif')
13281
    with TiffFile(fname) as tif:
13282
        assert tif.is_sis
13283
        assert tif.byteorder == '<'
13284
        assert len(tif.pages) == 1
13285
        assert len(tif.series) == 1
13286
        # assert page properties
13287
        page = tif.pages.first
13288
        assert page.imagewidth == 2560
13289
        assert page.imagelength == 1920
13290
        assert page.bitspersample == 8
13291
        assert page.samplesperpixel == 3
13292
        # assert metadata
13293
        sis = tif.sis_metadata
13294
        assert 'axes' not in sis
13295
        assert sis['magnification'] == 20.0
13296
        assert__str__(tif)
13297

13298

13299
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
13300
def test_read_sem_metadata():
13301
    """Test read Zeiss SEM metadata."""
13302
    # file from hyperspy tests
13303
    fname = private_file('hyperspy/test_tiff_Zeiss_SEM_1k.tif')
13304
    with TiffFile(fname) as tif:
13305
        assert tif.is_sem
13306
        assert tif.byteorder == '<'
13307
        assert len(tif.pages) == 1
13308
        assert len(tif.series) == 1
13309
        # assert page properties
13310
        page = tif.pages.first
13311
        assert page.is_contiguous
13312
        assert page.photometric == PHOTOMETRIC.PALETTE
13313
        assert page.imagewidth == 1024
13314
        assert page.imagelength == 768
13315
        assert page.bitspersample == 8
13316
        assert page.samplesperpixel == 1
13317
        # assert data and metadata
13318
        data = page.asrgb()
13319
        assert tuple(data[563, 320]) == (38550, 38550, 38550)
13320
        sem = tif.sem_metadata
13321
        assert sem[''][3] == 2.614514e-06
13322
        assert sem['ap_date'] == ('Date', '23 Dec 2015')
13323
        assert sem['ap_time'] == ('Time', '9:40:32')
13324
        assert sem['dp_image_store'] == ('Store resolution', '1024 * 768')
13325
        assert sem['ap_fib_fg_emission_actual'] == (
13326
            'Flood Gun Emission Actual',
13327
            0.0,
13328
            'µA',
13329
        )
13330
        assert_aszarr_method(tif)
13331
        assert__str__(tif)
13332

13333

13334
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
13335
def test_read_sem_bad_metadata():
13336
    """Test read Zeiss SEM metadata with wrong length."""
13337
    # reported by Klaus Schwarzburg on 8/27/2018
13338
    fname = private_file('issues/sem_bad_metadata.tif')
13339
    with TiffFile(fname) as tif:
13340
        assert tif.is_sem
13341
        assert tif.byteorder == '<'
13342
        assert len(tif.pages) == 1
13343
        assert len(tif.series) == 1
13344
        # assert page properties
13345
        page = tif.pages.first
13346
        assert page.is_contiguous
13347
        assert page.photometric == PHOTOMETRIC.PALETTE
13348
        assert page.imagewidth == 1024
13349
        assert page.imagelength == 768
13350
        assert page.bitspersample == 8
13351
        assert page.samplesperpixel == 1
13352
        # assert data and metadata
13353
        data = page.asrgb()
13354
        assert tuple(data[350, 150]) == (17476, 17476, 17476)
13355
        sem = tif.sem_metadata
13356
        assert sem['sv_version'][1] == 'V05.07.00.00 : 08-Jul-14'
13357
        assert_aszarr_method(tif)
13358
        assert__str__(tif)
13359

13360

13361
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
13362
def test_read_fei_metadata():
13363
    """Test read Helios FEI metadata."""
13364
    # file from hyperspy tests
13365
    fname = private_file('hyperspy/test_tiff_FEI_SEM.tif')
13366
    with TiffFile(fname) as tif:
13367
        assert tif.is_fei
13368
        assert tif.byteorder == '<'
13369
        assert len(tif.pages) == 1
13370
        assert len(tif.series) == 1
13371
        # assert page properties
13372
        page = tif.pages.first
13373
        assert page.is_contiguous
13374
        assert page.photometric != PHOTOMETRIC.PALETTE
13375
        assert page.imagewidth == 1536
13376
        assert page.imagelength == 1103
13377
        assert page.bitspersample == 8
13378
        assert page.samplesperpixel == 1
13379
        # assert data and metadata
13380
        data = page.asarray()
13381
        assert data[563, 320] == 220
13382
        fei = tif.fei_metadata
13383
        assert fei['User']['User'] == 'supervisor'
13384
        assert fei['System']['DisplayHeight'] == 0.324
13385
        assert_aszarr_method(tif)
13386
        assert__str__(tif)
13387

13388

13389
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_LARGE or SKIP_ZARR, reason=REASON)
13390
def test_read_mmstack_multifile(caplog):
13391
    """Test read MicroManager 2.0 multi-file, multi-position dataset."""
13392
    # TODO: what version of MicroManager does not write corrupted files?
13393
    # second ImageDescription tag value is beyond 4 GB
13394
    # MicroManager headers are beyond 4 GB
13395
    # MicroManager display settings are truncated
13396
    fname = private_file('MMStack/NDTiff.index/_4_MMStack_Pos0.ome.tif')
13397
    with TiffFile(fname) as tif:
13398
        assert 'coercing invalid ASCII to bytes' in caplog.text
13399
        assert tif.is_micromanager
13400
        assert tif.is_mmstack
13401
        assert tif.is_ome
13402
        assert not tif.is_imagej
13403
        assert not tif.is_ndtiff
13404
        assert tif.byteorder == '<'
13405
        assert len(tif.pages) == 8092
13406
        assert len(tif.series) == 1
13407
        assert 'failed to read display settings' not in caplog.text
13408
        assert 'failed to read comments: invalid header' not in caplog.text
13409
        # assert metadata
13410
        meta = tif.micromanager_metadata
13411
        assert meta is not None
13412
        assert meta['MajorVersion'] == 0
13413
        assert meta['Summary']['MicroManagerVersion'] == '2.0.0'
13414
        assert meta['Summary']['Prefix'] == '_4'
13415
        assert meta['IndexMap'].shape == (8092, 5)
13416
        assert 'Comments' in meta
13417
        # assert series properties
13418
        series = tif.series[0]
13419
        assert len(series) == 17472
13420
        assert series.shape == (91, 2, 48, 2, 512, 512)
13421
        assert series.axes == 'TRZCYX'
13422
        assert series.kind == 'mmstack'
13423
        assert series.is_multifile
13424
        # assert data
13425
        data = tif.asarray()
13426
        assert isinstance(data, numpy.ndarray)
13427
        assert data.shape == (91, 2, 48, 2, 512, 512)
13428
        assert data.dtype == numpy.uint16
13429
        assert data[48, 1, 23, 1, 253, 257] == 1236
13430
        # assert_aszarr_method(series, data)  # takes 2 minutes
13431
        with series.aszarr() as store:
13432
            data = zarr.open(store, mode='r')
13433
            assert data[48, 1, 23, 1, 253, 257] == 1236
13434
        # test OME; ImageJ can't handle multi-file or positions
13435
        assert_array_equal(data[:, 0], imread(fname, is_mmstack=False))
13436
        assert__str__(tif)
13437

13438

13439
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_LARGE, reason=REASON)
13440
def test_read_mmstack_mosaic(caplog):
13441
    """Test read MicroManager 1.4 mosaic dataset."""
13442
    fname = private_file(
13443
        'MMStack/mosaic/d220708_HybISS_AS_cycles1to5_NoBridgeProbes_dim3x3__3'
13444
        '_MMStack_2-Pos_000_001.ome.tif'
13445
    )
13446
    with TiffFile(fname) as tif:
13447
        assert 'coercing invalid ASCII to bytes' not in caplog.text
13448
        assert tif.is_micromanager
13449
        assert tif.is_mmstack
13450
        assert tif.is_ome
13451
        assert tif.is_imagej
13452
        assert not tif.is_ndtiff
13453
        assert tif.byteorder == '<'
13454
        assert len(tif.pages) == 55
13455
        assert len(tif.series) == 1
13456
        # assert metadata
13457
        meta = tif.micromanager_metadata
13458
        assert meta is not None
13459
        assert meta['MajorVersion'] == 0
13460
        assert meta['Summary']['MicroManagerVersion'] == '1.4.24 20220315'
13461
        assert meta['Summary']['Prefix'] == (
13462
            'd220708_HybISS_AS_cycles1to5_NoBridgeProbes_dim3x3__3'
13463
        )
13464
        assert meta['IndexMap'].shape == (55, 5)
13465
        assert 'Comments' in meta
13466
        # assert series properties
13467
        series = tif.series[0]
13468
        assert len(series) == 495
13469
        assert series.shape == (9, 11, 5, 1040, 1388)
13470
        assert series.axes == 'RZCYX'
13471
        assert series.kind == 'mmstack'
13472
        assert series.is_multifile
13473
        # assert data
13474
        data = tif.asarray()
13475
        assert isinstance(data, numpy.ndarray)
13476
        assert data.shape == (9, 11, 5, 1040, 1388)
13477
        assert data.dtype == numpy.uint16
13478
        assert data[7, 9, 3, 753, 1257] == 90
13479
        assert_aszarr_method(series, data)
13480
        assert__str__(tif)
13481

13482

13483
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_LARGE, reason=REASON)
13484
def test_read_mmstack_single():
13485
    """Test read MicroManager single-file multi-region dataset."""
13486
    fname = private_file(
13487
        'MMStack/181003_multi_pos_time_course_1_MMStack.ome.tif'
13488
    )
13489
    with TiffFile(fname) as tif:
13490
        assert tif.is_micromanager
13491
        assert tif.is_mmstack
13492
        assert tif.is_ome
13493
        assert tif.is_imagej
13494
        assert not tif.is_ndtiff
13495
        assert tif.byteorder == '<'
13496
        assert len(tif.pages) == 20
13497
        assert len(tif.series) == 1
13498
        # assert metadata
13499
        meta = tif.micromanager_metadata
13500
        assert meta is not None
13501
        assert meta['MajorVersion'] == 0
13502
        assert meta['Summary']['MicroManagerVersion'] == '2.0.0-beta3 20160512'
13503
        assert meta['Summary']['Prefix'] == '181003_multi_pos_time_course_1'
13504
        assert meta['IndexMap'].shape == (20, 5)
13505
        assert meta['Comments']['0_0_4_1'] == ''
13506
        # assert series properties
13507
        series = tif.series[0]
13508
        assert len(series) == 20
13509
        assert series.shape == (10, 2, 256, 256)
13510
        assert series.axes == 'TRYX'
13511
        assert series.kind == 'mmstack'
13512
        assert not series.is_multifile
13513
        # assert data
13514
        data = tif.asarray()
13515
        assert isinstance(data, numpy.ndarray)
13516
        assert data.shape == (10, 2, 256, 256)
13517
        assert data.dtype == numpy.uint16
13518
        assert data[7, 1, 111, 222] == 6991
13519
        assert_aszarr_method(series, data)
13520
        # test OME; ImageJ can't handle positions
13521
        assert_array_equal(data[:, 0], imread(fname, is_mmstack=False))
13522
        assert__str__(tif)
13523

13524

13525
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_LARGE, reason=REASON)
13526
def test_read_mmstack_missing(caplog):
13527
    """Test read MicroManager missing files and pages in dataset."""
13528
    fname = private_file('MMStack/movie_9_MMStack.ome.tif')
13529
    with TiffFile(fname) as tif:
13530
        assert tif.is_micromanager
13531
        assert tif.is_mmstack
13532
        assert tif.is_ome
13533
        assert tif.is_imagej
13534
        assert not tif.is_ndtiff
13535
        assert tif.byteorder == '<'
13536
        assert len(tif.pages) == 126
13537
        assert len(tif.series) == 1
13538
        assert 'MMStack series is missing files' in caplog.text
13539
        assert 'MMStack is missing 1 page' in caplog.text
13540
        # assert metadata
13541
        meta = tif.micromanager_metadata
13542
        assert meta is not None
13543
        assert meta['MajorVersion'] == 0
13544
        assert meta['Summary']['MicroManagerVersion'] == '1.4.16 20140128'
13545
        assert meta['Summary']['Prefix'] == 'movie_9'
13546
        assert meta['IndexMap'].shape == (125, 5)
13547
        assert meta['Comments'] == {'Summary': ''}
13548
        assert meta['DisplaySettings'][0]['Name'] == 'Dual-GFP'
13549
        # assert series properties
13550
        series = tif.series[0]
13551
        assert series[-1] is None  # missing page
13552
        assert len(series) == 126
13553
        assert series.shape == (63, 2, 264, 320)
13554
        assert series.axes == 'TCYX'
13555
        assert series.kind == 'mmstack'
13556
        assert not series.is_multifile
13557
        # assert data
13558
        data = tif.asarray()
13559
        assert isinstance(data, numpy.ndarray)
13560
        assert data.shape == (63, 2, 264, 320)
13561
        assert data.dtype == numpy.uint16
13562
        assert data[59, 1, 151, 186] == 599
13563
        # assert zarr
13564
        if not SKIP_ZARR and zarr is not None:
13565
            with series.aszarr(fillvalue=100) as store:
13566
                assert '1.1.0.0' in store
13567
                assert '62.1.0.0' not in store  # missing page
13568
                z = zarr.open(store, mode='r')
13569
                assert z[62, 1, 0, 0] == 100
13570
                assert_array_equal(data[:62], z[:62])
13571
        # test OME and ImageJ
13572
        assert_array_equal(data, imread(fname, is_mmstack=False))
13573
        assert_array_equal(data, imread(fname, is_mmstack=False, is_ome=False))
13574
        assert__str__(tif)
13575

13576

13577
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_LARGE, reason=REASON)
13578
def test_read_mmstack_bytesio(caplog):
13579
    """Test read MicroManager missing data in BytesIO."""
13580
    fname = private_file('MMStack/movie_9_MMStack.ome.tif')
13581
    with open(fname, 'rb') as fh:
13582
        bytesio = BytesIO(fh.read())
13583
    with TiffFile(bytesio) as tif:
13584
        assert tif.is_micromanager
13585
        assert tif.is_mmstack
13586
        assert tif.is_ome
13587
        assert tif.is_imagej
13588
        assert not tif.is_ndtiff
13589
        assert not tif.filehandle.is_file
13590
        assert tif.byteorder == '<'
13591
        assert len(tif.pages) == 126
13592
        assert len(tif.series) == 1
13593
        assert 'MMStack series is missing files' in caplog.text
13594
        assert 'MMStack is missing 1 page' in caplog.text
13595
        # assert metadata
13596
        meta = tif.micromanager_metadata
13597
        assert meta is not None
13598
        assert meta['MajorVersion'] == 0
13599
        assert meta['Summary']['MicroManagerVersion'] == '1.4.16 20140128'
13600
        assert meta['Summary']['Prefix'] == 'movie_9'
13601
        assert meta['IndexMap'].shape == (125, 5)
13602
        assert meta['Comments'] == {'Summary': ''}
13603
        assert meta['DisplaySettings'][0]['Name'] == 'Dual-GFP'
13604
        # assert series properties
13605
        series = tif.series[0]
13606
        assert len(series) == 126
13607
        assert series.shape == (63, 2, 264, 320)
13608
        assert series.axes == 'TCYX'
13609
        assert series.kind == 'mmstack'
13610
        assert not series.is_multifile
13611
        # assert data
13612
        data = tif.asarray()
13613
        assert isinstance(data, numpy.ndarray)
13614
        assert data.shape == (63, 2, 264, 320)
13615
        assert data.dtype == numpy.uint16
13616
        assert data[59, 1, 151, 186] == 599
13617
        assert_aszarr_method(series, data)
13618
        assert__str__(tif)
13619

13620

13621
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_LARGE, reason=REASON)
13622
def test_read_mmstack_missing_sbs(caplog):
13623
    """Test read MicroManager dataset with missing data."""
13624
    # https://github.com/cgohlke/tifffile/issues/187
13625
    fname = private_file('MMStack/10X_c1-SBS-1_A1_Tile-102.sbs.tif')
13626
    with TiffFile(fname) as tif:
13627
        assert tif.is_micromanager
13628
        assert tif.is_mmstack
13629
        assert tif.is_ome
13630
        assert tif.is_imagej
13631
        assert not tif.is_ndtiff
13632
        assert tif.byteorder == '<'
13633
        assert len(tif.pages) == 5
13634
        assert len(tif.series) == 1
13635
        assert 'MMStack file name is invalid' in caplog.text
13636
        assert 'MMStack series is missing files' in caplog.text
13637
        # assert metadata
13638
        meta = tif.micromanager_metadata
13639
        assert meta is not None
13640
        assert meta['MajorVersion'] == 0
13641
        assert meta['Summary']['MicroManagerVersion'].startswith('1.4.23 2019')
13642
        assert meta['Summary']['Prefix'] == '10X_c1-SBS-1_1'
13643
        assert meta['IndexMap'].shape == (5, 5)
13644
        assert meta['Comments']['Summary'] == ''
13645
        assert meta['DisplaySettings'][0]['Name'] == 'DAPI_10p'
13646
        # assert series properties
13647
        series = tif.series[0]
13648
        assert len(series) == 5
13649
        assert series.shape == (5, 1024, 1024)
13650
        assert series.axes == 'CYX'
13651
        assert series.kind == 'mmstack'
13652
        assert not series.is_multifile
13653
        # assert data
13654
        data = tif.asarray()
13655
        assert isinstance(data, numpy.ndarray)
13656
        assert data.shape == (5, 1024, 1024)
13657
        assert data.dtype == numpy.uint16
13658
        assert data[3, 151, 186] == 542
13659
        assert_aszarr_method(series, data)
13660
        # test OME
13661
        assert_array_equal(data, imread(fname, is_mmstack=False))
13662
        assert__str__(tif)
13663

13664

13665
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_LARGE, reason=REASON)
13666
def test_read_mmstack_trzc():
13667
    """Test read MicroManager 6 dimensional dataset."""
13668
    fname = private_file(
13669
        'MMStack'
13670
        '/image_stack_tpzc_50tp_2p_5z_3c_512k_1_MMStack_2-Pos000_000.ome.tif'
13671
    )
13672
    with TiffFile(fname) as tif:
13673
        assert tif.is_micromanager
13674
        assert tif.is_mmstack
13675
        assert tif.is_ome
13676
        assert tif.is_imagej
13677
        assert not tif.is_ndtiff
13678
        assert tif.byteorder == '<'
13679
        assert len(tif.pages) == 750
13680
        assert len(tif.series) == 1
13681
        # assert metadata
13682
        meta = tif.micromanager_metadata
13683
        assert meta is not None
13684
        assert meta['MajorVersion'] == 0
13685
        assert meta['Summary']['MicroManagerVersion'].startswith('2.0.0-gamma')
13686
        assert meta['Summary']['Prefix'] == (
13687
            'image_stack_tpzc_50tp_2p_5z_3c_512k_1'
13688
        )
13689
        assert meta['IndexMap'].shape == (750, 5)
13690
        assert meta['Comments']['Summary'] == ''
13691
        assert 'DisplaySettings' not in meta
13692
        # assert series properties
13693
        series = tif.series[0]
13694
        assert len(series) == 1500
13695
        assert series.shape == (50, 2, 5, 3, 256, 256)
13696
        assert series.axes == 'TRZCYX'
13697
        assert series.kind == 'mmstack'
13698
        assert series.is_multifile
13699
        # assert data
13700
        data = tif.asarray()
13701
        assert isinstance(data, numpy.ndarray)
13702
        assert data.shape == (50, 2, 5, 3, 256, 256)
13703
        assert data.dtype == numpy.uint16
13704
        assert data[27, 1, 3, 2, 151, 186] == 16
13705
        assert_aszarr_method(series, data)
13706
        # test OME
13707
        assert_array_equal(
13708
            data[:, 1], imread(fname, is_mmstack=False, series=1)
13709
        )
13710
        assert__str__(tif)
13711

13712

13713
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
13714
def test_read_ndtiff_magellanstack():
13715
    """Test read NDTiffStorage/MagellanStack."""
13716
    # https://github.com/cgohlke/tifffile/issues/23
13717
    fname = private_file(
13718
        'NDTiffStorage/MagellanStack/Full resolution/democam_MagellanStack.tif'
13719
    )
13720
    with TiffFile(fname) as tif:
13721
        assert tif.is_micromanager
13722
        assert len(tif.pages) == 12
13723
        # with pytest.warns(UserWarning):
13724
        assert tif.micromanager_metadata is not None
13725
        assert 'Comments' not in tif.micromanager_metadata
13726
        meta = tif.pages[-1].tags['MicroManagerMetadata'].value
13727
        assert meta['Axes']['repetition'] == 2
13728
        assert meta['Axes']['exposure'] == 3
13729
        # NDTiff v0 and v1 series are not supported
13730
        series = tif.series[0]
13731
        assert series.kind == 'uniform'  # not 'ndtiff'
13732
        assert series.dtype == numpy.uint8
13733
        assert series.shape == (12, 512, 512)
13734
        assert series.axes == 'IYX'
13735
        data = series.asarray()
13736
        assert data[8, 100, 100] == 164
13737
        assert_aszarr_method(tif, data)
13738
        assert__str__(tif)
13739

13740

13741
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
13742
def test_read_ndtiff_v2():
13743
    """Test read NDTiffStorage v2."""
13744
    fname = private_file(
13745
        'NDTiffStorage/v2/ndtiffv2.0_test/Full resolution'
13746
        '/ndtiffv2.0_test_NDTiffStack.tif'
13747
    )
13748
    with TiffFile(fname) as tif:
13749
        assert tif.is_micromanager
13750
        assert tif.is_ndtiff
13751
        meta = tif.pages[-1].tags['MicroManagerMetadata'].value
13752
        assert meta['Axes'] == {'channel': 1, 'time': 4}
13753
        meta = tif.micromanager_metadata
13754
        assert meta is not None
13755
        assert meta['MajorVersion'] == 2
13756
        assert meta['Summary']['PixelType'] == 'GRAY16'
13757
        series = tif.series[0]
13758
        assert series.kind == 'ndtiff'
13759
        assert series.dtype == numpy.uint16
13760
        assert series.shape == (5, 2, 32, 32)
13761
        assert series.axes == 'TCYX'
13762
        data = series.asarray()
13763
        if not SKIP_NDTIFF:
13764
            ndt = ndtiff.Dataset(os.path.join(os.path.dirname(fname), '..'))
13765
            try:
13766
                assert_array_equal(
13767
                    data, ndt.as_array(axes=['time', 'channel'])
13768
                )
13769
            finally:
13770
                ndt.close()
13771

13772
        assert_aszarr_method(tif, data)
13773
        assert__str__(tif)
13774

13775

13776
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
13777
def test_read_ndtiff_tiled():
13778
    """Test read NDTiffStorage v2 tiled."""
13779
    fname = private_file(
13780
        'NDTiffStorage/v2/ndtiffv2.0_stitched_test/Full resolution'
13781
        '/ndtiffv2.0_stitched_test_NDTiffStack.tif'
13782
    )
13783
    with TiffFile(fname) as tif:
13784
        assert tif.is_micromanager
13785
        assert tif.is_ndtiff
13786
        meta = tif.pages[-1].tags['MicroManagerMetadata'].value
13787
        assert meta['Axes'] == {'channel': 0, 'column': 0, 'row': 0}
13788
        meta = tif.micromanager_metadata
13789
        assert meta is not None
13790
        assert meta['MajorVersion'] == 2
13791
        assert meta['Summary']['PixelType'] == 'GRAY16'
13792
        series = tif.series[0]
13793
        assert series.kind == 'ndtiff'
13794
        assert series.dtype == numpy.uint16
13795
        assert series.shape == (2, 2, 32, 32)
13796
        assert series.axes == 'JKYX'
13797
        data = series.asarray()
13798
        if not SKIP_NDTIFF:
13799
            ndt = ndtiff.Dataset(os.path.join(os.path.dirname(fname), '..'))
13800
            try:
13801
                assert_array_equal(data, ndt.as_array(axes=['row', 'column']))
13802
            finally:
13803
                ndt.close()
13804
        assert_aszarr_method(tif, data)
13805
        assert__str__(tif)
13806

13807

13808
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
13809
def test_read_ndtiff_v3():
13810
    """Test read NDTiffStorage v3."""
13811
    fname = private_file(
13812
        'NDTiffStorage/v3/ndtiffv3.0_test/ndtiffv3.0_test_NDTiffStack.tif'
13813
    )
13814
    with TiffFile(fname) as tif:
13815
        assert tif.is_micromanager
13816
        assert tif.is_ndtiff
13817
        meta = tif.pages[-1].tags['MicroManagerMetadata'].value
13818
        assert meta['Axes'] == {'channel': 1, 'time': 4}
13819
        meta = tif.micromanager_metadata
13820
        assert meta is not None
13821
        assert meta['MajorVersion'] == 3
13822
        assert meta['MinorVersion'] == 0
13823
        assert meta['Summary']['PixelType'] == 'GRAY16'
13824
        series = tif.series[0]
13825
        assert series.kind == 'ndtiff'
13826
        assert series.dtype == numpy.uint16
13827
        assert series.shape == (5, 2, 32, 32)
13828
        assert series.axes == 'TCYX'
13829
        data = series.asarray()
13830
        if not SKIP_NDTIFF:
13831
            ndt = ndtiff.Dataset(os.path.dirname(fname))
13832
            try:
13833
                assert_array_equal(
13834
                    data, ndt.as_array(axes=['time', 'channel'])
13835
                )
13836
            finally:
13837
                ndt.close()
13838
        assert_aszarr_method(tif, data)
13839
        assert__str__(tif)
13840

13841

13842
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
13843
def test_read_ndtiff_tcz():
13844
    """Test read NDTiffStorage v3 with squeezed axes."""
13845
    fname = private_file(
13846
        'NDTiffStorage/v3/mm_mda_tcz_15/mm_mda_tcz_15_NDTiffStack.tif'
13847
    )
13848
    with TiffFile(fname) as tif:
13849
        assert tif.is_micromanager
13850
        assert tif.is_ndtiff
13851
        meta = tif.pages[-1].tags['MicroManagerMetadata'].value
13852
        assert 'Axes' not in meta  # missing?
13853
        # expected {'channel': 1, 'z': 6, 'position': 0, 'time': 7}
13854
        meta = tif.micromanager_metadata
13855
        assert meta is not None
13856
        assert meta['MajorVersion'] == 3
13857
        assert meta['MinorVersion'] == 0
13858
        assert meta['Summary']['PixelType'] == 'GRAY16'
13859
        series = tif.series[0]
13860
        assert series.kind == 'ndtiff'
13861
        assert series.dtype == numpy.uint16
13862
        assert series.get_shape(False) == (1, 8, 2, 7, 512, 512)
13863
        assert series.get_axes(False) == 'RTCZYX'
13864
        data = series.asarray(squeeze=True)
13865
        assert data.shape == (8, 2, 7, 512, 512)
13866
        if not SKIP_NDTIFF:
13867
            ndt = ndtiff.Dataset(os.path.dirname(fname))
13868
            try:
13869
                # axes=['position', 'time', 'channel', 'z']
13870
                assert_array_equal(data, numpy.squeeze(ndt.as_array()))
13871
            finally:
13872
                ndt.close()
13873
        assert_aszarr_method(tif, data)
13874
        assert__str__(tif)
13875

13876

13877
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
13878
def test_read_ndtiff_bytesio(caplog):
13879
    """Test read NDTiffStorage v3 with BytesIO."""
13880
    fname = private_file(
13881
        'NDTiffStorage/v3/mm_mda_tcz_15/mm_mda_tcz_15_NDTiffStack.tif'
13882
    )
13883
    with open(fname, 'rb') as fh:
13884
        bytesio = BytesIO(fh.read())
13885
    with TiffFile(bytesio) as tif:
13886
        assert tif.is_micromanager
13887
        assert tif.is_ndtiff
13888
        meta = tif.pages[-1].tags['MicroManagerMetadata'].value
13889
        assert 'Axes' not in meta  # missing?
13890
        # expected {'channel': 1, 'z': 6, 'position': 0, 'time': 7}
13891
        meta = tif.micromanager_metadata
13892
        assert meta is not None
13893
        assert meta['MajorVersion'] == 3
13894
        assert meta['MinorVersion'] == 0
13895
        assert meta['Summary']['PixelType'] == 'GRAY16'
13896
        series = tif.series[0]
13897
        assert 'NDTiff.index not found for' in caplog.text
13898
        assert series.kind == 'generic'  # not ndtiff
13899
        assert series.dtype == numpy.uint16
13900
        assert series.get_shape(False) == (112, 512, 512, 1)
13901
        assert series.get_axes(False) == 'IYXS'
13902
        data = series.asarray(squeeze=True)
13903
        assert data.shape == (112, 512, 512)
13904
        assert_aszarr_method(tif, data)
13905
        assert__str__(tif)
13906

13907

13908
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
13909
def test_read_ndtiff_multichannel():
13910
    """Test read NDTiffStorage v3 with channel names."""
13911
    fname = private_file(
13912
        'NDTiffStorage/v3/ndtiff3.2_multichannel'
13913
        '/NDTiff3.2_multichannel_NDTiffStack.tif'
13914
    )
13915
    with TiffFile(fname) as tif:
13916
        assert tif.is_micromanager
13917
        assert tif.is_ndtiff
13918
        meta = tif.pages[-1].tags['MicroManagerMetadata'].value
13919
        assert meta['Axes'] == {'channel': 'FITC', 'z': 15, 'time': 7}
13920
        meta = tif.micromanager_metadata
13921
        assert meta is not None
13922
        assert meta['MajorVersion'] == 3
13923
        assert meta['MinorVersion'] == 2
13924
        assert meta['Summary']['PixelType'] == 'GRAY16'
13925
        series = tif.series[0]
13926
        assert series.kind == 'ndtiff'
13927
        assert series.dtype == numpy.uint16
13928
        assert series.shape == (8, 2, 16, 64, 64)
13929
        assert series.axes == 'TCZYX'
13930
        data = series.asarray()
13931
        if not SKIP_NDTIFF:
13932
            ndt = ndtiff.Dataset(os.path.dirname(fname))
13933
            try:
13934
                assert_array_equal(
13935
                    data, ndt.as_array(axes=['time', 'channel', 'z'])
13936
                )
13937
            finally:
13938
                ndt.close()
13939
        assert_aszarr_method(tif, data)
13940
        assert__str__(tif)
13941

13942

13943
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_ZARR, reason=REASON)
13944
def test_read_zarr():
13945
    """Test read TIFF with zarr."""
13946
    fname = public_file('imagecodecs/gray.u1.tif')
13947
    with TiffFile(fname) as tif:
13948
        image = tif.asarray()
13949
        store = tif.aszarr()
13950
    try:
13951
        data = zarr.open(store, mode='r')
13952
        assert_array_equal(image, data)
13953
        del data
13954
    finally:
13955
        store.close()
13956

13957

13958
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_ZARR, reason=REASON)
13959
def test_read_zarr_lrucache():
13960
    """Test read TIFF with zarr LRUStoreCache."""
13961
    # fails with zarr 2.15/16
13962
    # https://github.com/zarr-developers/zarr-python/issues/1497
13963
    fname = public_file('imagecodecs/gray.u1.tif')
13964
    with TiffFile(fname) as tif:
13965
        image = tif.asarray()
13966
        store = tif.aszarr()
13967
    try:
13968
        cache = zarr.LRUStoreCache(store, max_size=2**10)
13969
        data = zarr.open(cache, mode='r')
13970
        assert_array_equal(image, data)
13971
        del data
13972
    finally:
13973
        store.close()
13974

13975

13976
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_ZARR, reason=REASON)
13977
def test_read_zarr_multifile():
13978
    """Test read multifile OME-TIFF with zarr."""
13979
    fname = public_file('OME/multifile/multifile-Z1.ome.tiff')
13980
    with TiffFile(fname) as tif:
13981
        image = tif.asarray()
13982
        store = tif.aszarr()
13983
    try:
13984
        data = zarr.open(store, mode='r')
13985
        assert_array_equal(image, data)
13986
        del data
13987
    finally:
13988
        store.close()
13989

13990

13991
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_ZARR, reason=REASON)
13992
@pytest.mark.parametrize('multiscales', [None, False, True])
13993
def test_read_zarr_multiscales(multiscales):
13994
    """Test Zarr store multiscales parameter."""
13995
    fname = public_file('tifffile/multiscene_pyramidal.ome.tif')
13996
    with TiffFile(fname) as tif:
13997
        page = tif.pages[1]
13998
        series = tif.series[0]
13999
        assert series.kind == 'ome'
14000
        image = page.asarray()
14001
        with page.aszarr(multiscales=multiscales) as store:
14002
            z = zarr.open(store, mode='r')
14003
            if multiscales:
14004
                assert isinstance(z, zarr.Group)
14005
                assert_array_equal(z[0][:], image)
14006
            else:
14007
                assert isinstance(z, zarr.Array)
14008
                assert_array_equal(z[:], image)
14009
            del z
14010
        with series.aszarr(multiscales=multiscales) as store:
14011
            z = zarr.open(store, mode='r')
14012
            if multiscales or multiscales is None:
14013
                assert isinstance(z, zarr.Group)
14014
                assert_array_equal(z[0][0, 0, 1], image)
14015
            else:
14016
                assert isinstance(z, zarr.Array)
14017
                assert_array_equal(z[0, 0, 1], image)
14018
            del z
14019

14020

14021
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_ZARR, reason=REASON)
14022
def test_read_zarr_level():
14023
    """Test Zarr store of level."""
14024
    fname = public_file('tifffile/multiscene_pyramidal.ome.tif')
14025
    data = imread(fname, key=1, series=0, level=2)
14026
    store = imread(fname, key=1, series=0, level=2, aszarr=True)
14027
    z = zarr.open(store, mode='r')
14028
    image = z[:]
14029
    del z
14030
    assert_array_equal(image, data)
14031

14032

14033
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
14034
def test_read_eer(caplog):
14035
    """Test read EER metadata."""
14036
    # https://github.com/fei-company/EerReaderLib/issues/1
14037
    fname = private_file('EER/Example_1.eer')
14038
    with TiffFile(fname) as tif:
14039
        assert not caplog.text  # no warning
14040
        assert tif.is_bigtiff
14041
        assert tif.is_eer
14042
        assert tif.byteorder == '<'
14043
        assert len(tif.pages) == 238
14044
        assert len(tif.series) == 1
14045
        # assert page properties
14046
        page = tif.pages.first
14047
        assert not page.is_contiguous
14048
        assert page.photometric == PHOTOMETRIC.MINISBLACK
14049
        assert page.compression == 65001
14050
        assert page.imagewidth == 4096
14051
        assert page.imagelength == 4096
14052
        assert page.bitspersample == 1
14053
        assert page.samplesperpixel == 1
14054
        meta = tif.eer_metadata
14055
        assert meta.startswith('<metadata>')
14056
        # assert data
14057
        data = page.asarray()
14058
        assert data.dtype == '?'
14059
        assert data[428, 443]
14060
        assert not data[428, 444]
14061
        assert_aszarr_method(page, data)
14062
        assert__str__(tif)
14063

14064
        if not SKIP_ZARR:
14065
            try:
14066
                from imagecodecs.numcodecs import register_codecs
14067
            except ImportError:
14068
                return
14069
            register_codecs('imagecodecs_eer', verbose=False)
14070
            filename = os.path.split(fname)[-1]
14071
            url = URL + 'test/private/EER/'
14072
            with TempFileName(filename, ext='.json') as jsonfile:
14073
                with page.aszarr() as store:
14074
                    store.write_fsspec(jsonfile, url)
14075
                # if this fails add ".eer" as "image/tiff" to mime types
14076
                assert_fsspec(URL + os.path.split(jsonfile)[-1], data)
14077

14078

14079
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
14080
def test_read_astrotiff(caplog):
14081
    """Test read AstroTIFF with FITS metadata."""
14082
    # https://astro-tiff.sourceforge.io/
14083
    fname = private_file('AstroTIFF/NGC2024_astro-tiff_sample_48bit.tif')
14084
    with TiffFile(fname) as tif:
14085
        assert not caplog.text  # no warning
14086
        assert tif.is_astrotiff
14087
        assert tif.byteorder == '<'
14088
        assert len(tif.pages) == 1
14089
        assert len(tif.series) == 1
14090
        # assert page properties
14091
        page = tif.pages.first
14092
        assert not page.is_contiguous
14093
        assert page.photometric == PHOTOMETRIC.RGB
14094
        assert page.compression == COMPRESSION.ADOBE_DEFLATE
14095
        assert page.imagewidth == 3040
14096
        assert page.imagelength == 2016
14097
        assert page.bitspersample == 16
14098
        assert page.samplesperpixel == 3
14099
        # assert data and metadata
14100
        assert tuple(page.asarray()[545, 1540]) == (10401, 11804, 12058)
14101
        meta = tif.astrotiff_metadata
14102
        assert meta['SIMPLE']
14103
        assert meta['APTDIA'] == 100.0
14104
        assert meta['APTDIA:COMMENT'] == 'Aperture diameter of telescope in mm'
14105
        assert__str__(tif)
14106

14107

14108
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
14109
def test_read_streak():
14110
    """Test read Hamamatus Streak file."""
14111
    fname = private_file('HamamatsuStreak/hamamatsu_streak.tif')
14112
    with TiffFile(fname) as tif:
14113
        assert tif.is_streak
14114
        assert tif.byteorder == '<'
14115
        assert len(tif.pages) == 1
14116
        assert len(tif.series) == 1
14117
        # assert page properties
14118
        page = tif.pages.first
14119
        assert page.is_contiguous
14120
        assert page.photometric == PHOTOMETRIC.MINISBLACK
14121
        assert page.imagewidth == 672
14122
        assert page.imagelength == 508
14123
        assert page.bitspersample == 16
14124
        assert page.samplesperpixel == 1
14125
        # assert data and metadata
14126
        assert page.asarray()[277, 341] == 47
14127
        meta = tif.streak_metadata
14128
        assert meta['Application']['SoftwareVersion'] == '9.5 pf4'
14129
        assert meta['Acquisition']['areSource'] == (0, 0, 672, 508)
14130
        assert meta['Camera']['Prop_InternalLineInterval'] == 9.74436e-06
14131
        assert meta['Camera']['Prop_OutputTriggerPeriod_2'] == 0.000001
14132
        assert meta['Camera']['HWidth'] == 672
14133
        assert meta['DisplayLUT']['EntrySize'] == 4
14134
        assert meta['Spectrograph']['Front Ent. Slitw.'] == 0
14135
        assert meta['Scaling']['ScalingYScalingFile'] == 'Focus mode'
14136
        xscale = meta['Scaling']['ScalingXScaling']
14137
        assert xscale.size == 672
14138
        assert xscale[0] == 231.09092712402344
14139
        assert xscale[-1] == 242.59259033203125
14140
        assert__str__(tif)
14141

14142

14143
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
14144
def test_read_agilent():
14145
    """Test read Agilent Technologies file."""
14146
    fname = private_file('Agilent/SG11410002_253174651388_S001.tif')
14147
    with TiffFile(fname) as tif:
14148
        assert tif.is_agilent
14149
        assert not tif.is_mdgel
14150
        assert len(tif.pages) == 4
14151
        assert len(tif.series) == 2
14152
        # assert page properties
14153
        page = tif.pages.first
14154
        assert page.is_contiguous
14155
        assert page.photometric == PHOTOMETRIC.MINISBLACK
14156
        assert page.imagewidth == 20334
14157
        assert page.imagelength == 7200
14158
        assert page.bitspersample == 16
14159
        assert page.samplesperpixel == 1
14160
        assert page.tags[285].value == 'Red'
14161
        assert page.tags[37702].value == 'Unknown'
14162
        # assert data
14163
        series = tif.series[0]
14164
        assert series.shape == (2, 7200, 20334)
14165
        assert series.asarray()[1, 277, 341] == 24
14166
        series = tif.series[1]
14167
        assert series.shape == (2, 2400, 6778)
14168
        assert series.asarray()[1, 277, 341] == 634
14169
        assert__str__(tif)
14170

14171

14172
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_ZARR, reason=REASON)
14173
@pytest.mark.parametrize('chunkmode', [0, 2])
14174
def test_read_selection(chunkmode):
14175
    """Test read selection via imread."""
14176
    fname = public_file('tifffile/multiscene_pyramidal.ome.tif')
14177
    selection = (8, slice(16, 17), slice(None), slice(51, 99), slice(51, 99))
14178
    # series 0
14179
    assert_array_equal(
14180
        imread(fname)[8, 16:17, :, 51:99, 51:99],
14181
        imread(fname, selection=selection, chunkmode=chunkmode),
14182
    )
14183
    # level 1
14184
    assert_array_equal(
14185
        imread(fname, series=0, level=1)[8, 16:17, :, 51:99, 51:99],
14186
        imread(
14187
            fname, series=0, level=1, selection=selection, chunkmode=chunkmode
14188
        ),
14189
    )
14190
    # page 99
14191
    assert_array_equal(
14192
        imread(fname, key=99)[51:99, 51:99],
14193
        imread(
14194
            fname,
14195
            key=99,
14196
            selection=(slice(51, 99), slice(51, 99)),
14197
            chunkmode=chunkmode,
14198
        ),
14199
    )
14200
    # series 1
14201
    assert_array_equal(
14202
        imread(fname, series=1)[51:99, 51:99],
14203
        imread(
14204
            fname,
14205
            series=1,
14206
            selection=(slice(51, 99), slice(51, 99)),
14207
            chunkmode=chunkmode,
14208
        ),
14209
    )
14210

14211

14212
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_ZARR, reason=REASON)
14213
@pytest.mark.parametrize('out', [None, 'empty', 'memmap', 'name'])
14214
def test_read_selection_out(out):
14215
    """Test read selection via imread into out."""
14216
    # https://github.com/cgohlke/tifffile/pull/222
14217
    fname = public_file('tifffile/multiscene_pyramidal.ome.tif')
14218
    selection = (8, slice(16, 17), slice(None), slice(51, 99), slice(51, 99))
14219
    expected = imread(fname)[8, 16:17, :, 51:99, 51:99]
14220
    if out is None:
14221
        # new array
14222
        image = imread(fname, selection=selection, out=None)
14223
    elif out == 'empty':
14224
        # existing array
14225
        image = numpy.empty_like(expected)
14226
        imread(fname, selection=selection, out=image)
14227
    elif out == 'memmap':
14228
        # memmap in temp dir
14229
        image = imread(fname, selection=selection, out='memmap')
14230
        assert isinstance(image, numpy.memmap)
14231
    elif out == 'name':
14232
        # memmap in specified file
14233
        with TempFileName('read_selection_out', ext='.memmap') as fileout:
14234
            image = imread(fname, selection=selection, out=fileout)
14235
            assert isinstance(image, numpy.memmap)
14236

14237
    assert_array_equal(image, expected)
14238

14239

14240
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
14241
def test_read_selection_filesequence():
14242
    """Test read selection from file sequence via imread."""
14243
    fname = private_file('TiffSequence/*.tif')
14244
    assert_array_equal(
14245
        imread(fname)[5:8, 51:99, 51:99],
14246
        imread(fname, selection=(slice(5, 8), slice(51, 99), slice(51, 99))),
14247
    )
14248

14249

14250
def test_read_xarray_page_properties():
14251
    """Test read TiffPage xarray properties."""
14252
    dtype = numpy.uint8
14253
    resolution = (1.1, 2.2)
14254
    with TempFileName('read_xarray_page_properties') as fname:
14255
        with TiffWriter(fname) as tif:
14256
            # gray
14257
            tif.write(
14258
                shape=(33, 31),
14259
                dtype=dtype,
14260
                resolution=resolution,
14261
                photometric='minisblack',
14262
            )
14263
            # RGB
14264
            tif.write(
14265
                shape=(33, 31, 3),
14266
                dtype=dtype,
14267
                resolution=resolution,
14268
                photometric='rgb',
14269
            )
14270
            # RGBA
14271
            tif.write(
14272
                shape=(33, 31, 4),
14273
                dtype=dtype,
14274
                resolution=resolution,
14275
                photometric='rgb',
14276
            )
14277
            # CMYK
14278
            tif.write(
14279
                shape=(33, 31, 4),
14280
                dtype=dtype,
14281
                resolution=resolution,
14282
                photometric='separated',
14283
            )
14284
            # gray with extrasamples
14285
            tif.write(
14286
                shape=(33, 31, 5),
14287
                dtype=dtype,
14288
                resolution=resolution,
14289
                photometric='minisblack',
14290
                planarconfig='contig',
14291
            )
14292
            # RRGGBB
14293
            tif.write(
14294
                shape=(3, 33, 31),
14295
                dtype=dtype,
14296
                resolution=resolution,
14297
                photometric='rgb',
14298
                planarconfig='separate',
14299
            )
14300
            # depth
14301
            tif.write(
14302
                shape=(7, 33, 31),
14303
                dtype=dtype,
14304
                resolution=resolution,
14305
                photometric='minisblack',
14306
                volumetric=True,
14307
            )
14308

14309
        xcoords = numpy.linspace(
14310
            0, 31 / resolution[0], 31, endpoint=False, dtype=numpy.float32
14311
        )
14312
        ycoords = numpy.linspace(
14313
            0, 33 / resolution[1], 33, endpoint=False, dtype=numpy.float32
14314
        )
14315
        # zcoords = numpy.linspace(
14316
        #     0, 7 / 1, 7, endpoint=False, dtype=numpy.float32
14317
        # )
14318
        with TiffFile(fname) as tif:
14319
            # gray
14320
            page = tif.pages.first
14321
            assert page.name == 'TiffPage 0'
14322
            assert page.shape == (33, 31)
14323
            assert page.ndim == 2
14324
            assert page.axes == 'YX'
14325
            assert page.dims == ('height', 'width')
14326
            assert page.sizes == {'height': 33, 'width': 31}
14327
            assert_array_equal(page.coords['height'], ycoords)
14328
            assert_array_equal(page.coords['width'], xcoords)
14329
            assert page.attr == {}
14330

14331
            # RGB
14332
            page = tif.pages[1]
14333
            assert page.name == 'TiffPage 1'
14334
            assert page.shape == (33, 31, 3)
14335
            assert page.ndim == 3
14336
            assert page.axes == 'YXS'
14337
            assert page.dims == ('height', 'width', 'sample')
14338
            assert page.sizes == {'height': 33, 'width': 31, 'sample': 3}
14339
            assert_array_equal(
14340
                page.coords['sample'], numpy.array(['Red', 'Green', 'Blue'])
14341
            )
14342
            assert_array_equal(page.coords['height'], ycoords)
14343
            assert_array_equal(page.coords['width'], xcoords)
14344

14345
            # RGBA
14346
            page = tif.pages[2]
14347
            assert page.name == 'TiffPage 2'
14348
            assert page.shape == (33, 31, 4)
14349
            assert page.ndim == 3
14350
            assert page.axes == 'YXS'
14351
            assert page.dims == ('height', 'width', 'sample')
14352
            assert page.sizes == {'height': 33, 'width': 31, 'sample': 4}
14353
            assert_array_equal(
14354
                page.coords['sample'],
14355
                numpy.array(['Red', 'Green', 'Blue', 'Unassalpha']),
14356
            )
14357
            assert_array_equal(page.coords['height'], ycoords)
14358
            assert_array_equal(page.coords['width'], xcoords)
14359

14360
            # CMYK
14361
            page = tif.pages[3]
14362
            assert page.name == 'TiffPage 3'
14363
            assert page.shape == (33, 31, 4)
14364
            assert page.ndim == 3
14365
            assert page.axes == 'YXS'
14366
            assert page.dims == ('height', 'width', 'sample')
14367
            assert page.sizes == {'height': 33, 'width': 31, 'sample': 4}
14368
            assert_array_equal(
14369
                page.coords['sample'],
14370
                numpy.array(['Cyan', 'Magenta', 'Yellow', 'Black']),
14371
            )
14372
            assert_array_equal(page.coords['height'], ycoords)
14373
            assert_array_equal(page.coords['width'], xcoords)
14374

14375
            # gray with extrasamples
14376
            page = tif.pages[4]
14377
            assert page.name == 'TiffPage 4'
14378
            assert page.shape == (33, 31, 5)
14379
            assert page.ndim == 3
14380
            assert page.axes == 'YXS'
14381
            assert page.dims == ('height', 'width', 'sample')
14382
            assert page.sizes == {'height': 33, 'width': 31, 'sample': 5}
14383
            assert_array_equal(
14384
                page.coords['sample'],
14385
                numpy.arange(5),
14386
            )
14387
            assert_array_equal(page.coords['height'], ycoords)
14388
            assert_array_equal(page.coords['width'], xcoords)
14389

14390
            # RRGGBB
14391
            page = tif.pages[5]
14392
            assert page.name == 'TiffPage 5'
14393
            assert page.shape == (3, 33, 31)
14394
            assert page.ndim == 3
14395
            assert page.axes == 'SYX'
14396
            assert page.dims == ('sample', 'height', 'width')
14397
            assert page.sizes == {'sample': 3, 'height': 33, 'width': 31}
14398
            assert_array_equal(
14399
                page.coords['sample'], numpy.array(['Red', 'Green', 'Blue'])
14400
            )
14401
            assert_array_equal(page.coords['height'], ycoords)
14402
            assert_array_equal(page.coords['width'], xcoords)
14403

14404
            # depth
14405
            page = tif.pages[6]
14406
            assert page.name == 'TiffPage 6'
14407
            assert page.shape == (7, 33, 31)
14408
            assert page.ndim == 3
14409
            assert page.axes == 'ZYX'
14410
            assert page.dims == ('depth', 'height', 'width')
14411
            assert page.sizes == {'depth': 7, 'height': 33, 'width': 31}
14412
            assert_array_equal(page.coords['depth'], numpy.arange(7))
14413
            assert_array_equal(page.coords['height'], ycoords)
14414
            assert_array_equal(page.coords['width'], xcoords)
14415

14416

14417
###############################################################################
14418

14419
# Test TiffWriter
14420

14421
WRITE_DATA = numpy.arange(3 * 219 * 301).astype(numpy.uint16)
14422
WRITE_DATA.shape = (3, 219, 301)
14423

14424

14425
@pytest.mark.skipif(SKIP_EXTENDED, reason=REASON)
14426
@pytest.mark.parametrize(
14427
    'shape',
14428
    [
14429
        (219, 301),
14430
        (219, 301, 2),
14431
        (219, 301, 3),
14432
        (219, 301, 4),
14433
        (2, 219, 301),
14434
        (3, 219, 301),
14435
        (4, 219, 301),
14436
        (5, 219, 301),
14437
        (4, 3, 219, 301),
14438
        (4, 219, 301, 3),
14439
        (3, 4, 219, 301),
14440
        (3, 4, 219, 301, 1),
14441
    ],
14442
)
14443
@pytest.mark.parametrize(
14444
    'compression', [None]  # , 'zlib', 'lzw', 'lzma', 'zstd', 'packbits']
14445
)
14446
@pytest.mark.parametrize('dtype', list('?bhiqefdBHIQFD'))
14447
@pytest.mark.parametrize('byteorder', ['>', '<'])
14448
@pytest.mark.parametrize('bigtiff', ['plaintiff', 'bigtiff'])
14449
@pytest.mark.parametrize('tile', [None, (64, 64)])
14450
@pytest.mark.parametrize('data', ['random', None])
14451
def test_write(data, byteorder, bigtiff, compression, dtype, shape, tile):
14452
    """Test TiffWriter with various options."""
14453
    if compression is not None and (data is None or SKIP_CODECS):
14454
        pytest.xfail(REASON)
14455
    fname = 'write_{}_{}_{}_{}{}{}{}'.format(
14456
        bigtiff,
14457
        {'<': 'le', '>': 'be'}[byteorder],
14458
        numpy.dtype(dtype).name,
14459
        str(shape).replace(' ', ''),
14460
        '_tiled' if tile is not None else '',
14461
        '_empty' if data is None else '',
14462
        f'_{compression}' if compression is not None else '',
14463
    )
14464
    bigtiff = bigtiff == 'bigtiff'
14465
    if (3 in shape or 4 in shape) and shape[-1] != 1 and dtype != '?':
14466
        photometric = 'rgb'
14467
    else:
14468
        photometric = None
14469

14470
    with TempFileName(fname) as fname:
14471
        if data is None:
14472
            with TiffWriter(
14473
                fname, byteorder=byteorder, bigtiff=bigtiff
14474
            ) as tif:
14475
                if dtype == '?':
14476
                    # cannot write non-contiguous empty file
14477
                    with pytest.raises(ValueError):
14478
                        tif.write(
14479
                            shape=shape,
14480
                            dtype=dtype,
14481
                            tile=tile,
14482
                            photometric=photometric,
14483
                        )
14484
                    return
14485
                tif.write(
14486
                    shape=shape,
14487
                    dtype=dtype,
14488
                    tile=tile,
14489
                    photometric=photometric,
14490
                )
14491
                assert__repr__(tif)
14492
            with TiffFile(fname) as tif:
14493
                assert__str__(tif)
14494
                image = tif.asarray()
14495
        else:
14496
            data = random_data(dtype, shape)
14497
            imwrite(
14498
                fname,
14499
                data,
14500
                byteorder=byteorder,
14501
                bigtiff=bigtiff,
14502
                tile=tile,
14503
                photometric=photometric,
14504
                compression=compression,
14505
            )
14506
            image = imread(fname)
14507
            assert image.flags['C_CONTIGUOUS']
14508
            assert_array_equal(data.squeeze(), image.squeeze())
14509
            if not SKIP_ZARR:
14510
                with imread(fname, aszarr=True) as store:
14511
                    data = zarr.open(store, mode='r')
14512
                    assert_array_equal(data, image)
14513

14514
        assert shape == image.shape
14515
        assert dtype == image.dtype
14516
        if not bigtiff:
14517
            assert_valid_tiff(fname)
14518

14519

14520
def test_write_deprecated_planarconfig():
14521
    """Test deprecated planarconfig."""
14522
    with TempFileName('write_deprecated_planarconfig_contig') as fname:
14523
        with pytest.warns(DeprecationWarning):
14524
            imwrite(fname, shape=(31, 33, 3), dtype=numpy.float32)
14525
        with TiffFile(fname) as tif:
14526
            page = tif.pages.first
14527
            assert page.photometric == PHOTOMETRIC.RGB
14528
            assert page.planarconfig == PLANARCONFIG.CONTIG
14529

14530
    with TempFileName('write_deprecated_planarconfig_separate') as fname:
14531
        with pytest.warns(DeprecationWarning):
14532
            imwrite(fname, shape=(3, 31, 33), dtype=numpy.float32)
14533
        with TiffFile(fname) as tif:
14534
            page = tif.pages.first
14535
            assert page.photometric == PHOTOMETRIC.RGB
14536
            assert page.planarconfig == PLANARCONFIG.SEPARATE
14537

14538

14539
def test_write_ycbcr_subsampling(caplog):
14540
    """Test write YCBCR."""
14541
    with TempFileName('write_ycbcr_subsampling') as fname:
14542
        imwrite(
14543
            fname,
14544
            shape=(31, 33, 3),
14545
            dtype=numpy.uint8,
14546
            photometric=PHOTOMETRIC.YCBCR,
14547
            subsampling=(1, 2),
14548
        )
14549
        assert 'cannot apply subsampling' in caplog.text
14550
        with TiffFile(fname) as tif:
14551
            page = tif.pages.first
14552
            assert page.photometric == PHOTOMETRIC.YCBCR
14553
            assert page.subsampling == (1, 1)
14554
            assert 'ReferenceBlackWhite' in page.tags
14555

14556

14557
@pytest.mark.parametrize('samples', [0, 1, 2])
14558
def test_write_invalid_samples(samples):
14559
    """Test TiffWriter with invalid options."""
14560
    data = numpy.zeros((16, 16, samples) if samples else (16, 16), numpy.uint8)
14561
    fname = f'write_invalid_samples{samples}'
14562
    with TempFileName(fname) as fname:
14563
        with pytest.raises(ValueError):
14564
            imwrite(fname, data, photometric='rgb')
14565

14566

14567
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_CODECS, reason=REASON)
14568
@pytest.mark.parametrize('tile', [False, True])
14569
@pytest.mark.parametrize(
14570
    'codec',
14571
    [
14572
        'adobe_deflate',
14573
        'lzma',
14574
        'lzw',
14575
        'packbits',
14576
        'zstd',
14577
        'webp',
14578
        'png',
14579
        'jpeg',
14580
        'jpegxl',
14581
        'jpegxr',
14582
        'jpeg2000',
14583
    ],
14584
)
14585
@pytest.mark.parametrize('mode', ['gray', 'rgb', 'planar'])
14586
def test_write_codecs(mode, tile, codec):
14587
    """Test write various compression."""
14588
    if mode in {'gray', 'planar'} and codec == 'webp':
14589
        pytest.xfail("WebP doesn't support grayscale or planar mode")
14590
    level = {'webp': -1, 'jpeg': 99}.get(codec, None)
14591
    if level:
14592
        compressionargs = {'level': level}
14593
    else:
14594
        compressionargs = None
14595
    tile = (16, 16) if tile else None
14596
    data = numpy.load(public_file('tifffile/rgb.u1.npy'))
14597
    if mode == 'rgb':
14598
        photometric = PHOTOMETRIC.RGB
14599
        planarconfig = PLANARCONFIG.CONTIG
14600
    elif mode == 'planar':
14601
        photometric = PHOTOMETRIC.RGB
14602
        planarconfig = PLANARCONFIG.SEPARATE
14603
        data = numpy.moveaxis(data, -1, 0).copy()
14604
    else:
14605
        planarconfig = None
14606
        photometric = PHOTOMETRIC.MINISBLACK
14607
        data = data[..., :1].copy()
14608
    data = numpy.repeat(data[numpy.newaxis], 3, axis=0)
14609
    data[1] = 255 - data[1]
14610
    shape = data.shape
14611
    with TempFileName(
14612
        'write_codecs_{}_{}{}'.format(mode, codec, '_tile' if tile else '')
14613
    ) as fname:
14614
        imwrite(
14615
            fname,
14616
            data,
14617
            compression=codec,
14618
            compressionargs=compressionargs,
14619
            tile=tile,
14620
            photometric=photometric,
14621
            planarconfig=planarconfig,
14622
            subsampling=(1, 1),
14623
        )
14624
        assert_valid_tiff(fname)
14625
        with TiffFile(fname) as tif:
14626
            assert len(tif.pages) == shape[0]
14627
            page = tif.pages.first
14628
            assert not page.is_contiguous
14629
            assert page.compression == enumarg(COMPRESSION, codec)
14630
            assert page.photometric in {photometric, PHOTOMETRIC.YCBCR}
14631
            if planarconfig is not None:
14632
                assert page.planarconfig == planarconfig
14633
            assert page.imagewidth == 31
14634
            assert page.imagelength == 32
14635
            assert page.samplesperpixel == 1 if mode == 'gray' else 3
14636
            # samplesperpixel = page.samplesperpixel
14637
            image = tif.asarray()
14638
            if codec == 'jpeg':
14639
                assert_allclose(data, image, atol=10)
14640
            else:
14641
                assert_array_equal(data, image)
14642
            assert_decode_method(page)
14643
            assert__str__(tif)
14644
        if (
14645
            imagecodecs.TIFF.available
14646
            and codec not in {'png', 'jpegxr', 'jpeg2000', 'jpegxl'}
14647
            and mode != 'planar'
14648
        ):
14649
            im = imagecodecs.imread(fname, index=None)
14650
            # if codec == 'jpeg':
14651
            #     # tiff_decode returns JPEG compressed TIFF as RGBA
14652
            #     im = numpy.squeeze(im[..., :samplesperpixel])
14653
            assert_array_equal(im, numpy.squeeze(image))
14654

14655

14656
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
14657
@pytest.mark.parametrize('mode', ['gray', 'rgb', 'planar'])
14658
@pytest.mark.parametrize('tile', [False, True])
14659
@pytest.mark.parametrize(
14660
    'dtype', ['u1', 'u2', 'u4', 'i1', 'i2', 'i4', 'f2', 'f4', 'f8']
14661
)
14662
@pytest.mark.parametrize('byteorder', ['>', '<'])
14663
def test_write_predictor(byteorder, dtype, tile, mode):
14664
    """Test predictors."""
14665
    if dtype[0] == 'f' and SKIP_CODECS:
14666
        pytest.xfail('requires imagecodecs')
14667
    tile = (32, 32) if tile else None
14668
    f4 = imread(public_file('tifffile/gray.f4.tif'))
14669
    if mode == 'rgb':
14670
        photometric = PHOTOMETRIC.RGB
14671
        planarconfig = PLANARCONFIG.CONTIG
14672
        data = numpy.empty((83, 111, 3), 'f4')
14673
        data[..., 0] = f4
14674
        data[..., 1] = f4[::-1]
14675
        data[..., 2] = f4[::-1, ::-1]
14676
    elif mode == 'planar':
14677
        photometric = PHOTOMETRIC.RGB
14678
        planarconfig = PLANARCONFIG.SEPARATE
14679
        data = numpy.empty((3, 83, 111), 'f4')
14680
        data[0] = f4
14681
        data[1] = f4[::-1]
14682
        data[2] = f4[::-1, ::-1]
14683
    else:
14684
        planarconfig = None
14685
        photometric = PHOTOMETRIC.MINISBLACK
14686
        data = f4
14687

14688
    if dtype[0] in 'if':
14689
        data -= 0.5
14690
    if dtype in 'u1i1':
14691
        data *= 255
14692
    elif dtype in 'i2u2':
14693
        data *= 2**12
14694
    elif dtype in 'i4u4':
14695
        data *= 2**21
14696
    else:
14697
        data *= 3.145
14698
    data = data.astype(byteorder + dtype)
14699

14700
    with TempFileName(
14701
        'write_predictor_{}_{}_{}{}'.format(
14702
            dtype,
14703
            'be' if byteorder == '>' else 'le',
14704
            mode,
14705
            '_tile' if tile else '',
14706
        )
14707
    ) as fname:
14708
        imwrite(
14709
            fname,
14710
            data,
14711
            predictor=True,
14712
            compression=COMPRESSION.ADOBE_DEFLATE,
14713
            tile=tile,
14714
            photometric=photometric,
14715
            planarconfig=planarconfig,
14716
            byteorder=byteorder,
14717
        )
14718
        assert_valid_tiff(fname)
14719

14720
        with TiffFile(fname) as tif:
14721
            assert tif.tiff.byteorder == byteorder
14722
            assert len(tif.pages) == 1
14723
            page = tif.pages.first
14724
            assert not page.is_contiguous
14725
            assert page.compression == COMPRESSION.ADOBE_DEFLATE
14726
            assert page.predictor == (3 if dtype[0] == 'f' else 2)
14727
            assert page.photometric == photometric
14728
            if planarconfig is not None:
14729
                assert page.planarconfig == planarconfig
14730
            assert page.imagewidth == 111
14731
            assert page.imagelength == 83
14732
            assert page.samplesperpixel == 1 if mode == 'gray' else 3
14733
            # samplesperpixel = page.samplesperpixel
14734
            image = tif.asarray()
14735
            assert_array_equal(data, image)
14736
            assert_decode_method(page)
14737
            assert__str__(tif)
14738

14739
        if not SKIP_CODECS and imagecodecs.TIFF.available:
14740
            im = imagecodecs.imread(fname, index=None)
14741
            assert_array_equal(im, numpy.squeeze(image))
14742

14743

14744
@pytest.mark.parametrize('bytecount', [16, 256])
14745
@pytest.mark.parametrize('count', [1, 2, 4])
14746
@pytest.mark.parametrize('compression', [0, 6])
14747
@pytest.mark.parametrize('tiled', [0, 1])
14748
@pytest.mark.parametrize('bigtiff', [0, 1])
14749
def test_write_bytecount(bigtiff, tiled, compression, count, bytecount):
14750
    """Test write bytecount formats."""
14751
    if tiled:
14752
        tag = 'TileByteCounts'
14753
        rowsperstrip = None
14754
        tile = (bytecount, bytecount)
14755
        shape = {
14756
            1: (bytecount, bytecount),
14757
            2: (bytecount * 2, bytecount),
14758
            4: (bytecount * 2, bytecount * 2),
14759
        }[count]
14760
        is_contiguous = count != 4 and compression == 0
14761
    else:
14762
        tag = 'StripByteCounts'
14763
        tile = None
14764
        rowsperstrip = bytecount
14765
        shape = (bytecount * count, bytecount)
14766
        is_contiguous = compression == 0
14767
    data = random_data(numpy.uint8, shape)
14768

14769
    if count == 1:
14770
        dtype = DATATYPE.LONG8 if bigtiff else DATATYPE.LONG
14771
    elif bytecount == 256:
14772
        dtype = DATATYPE.LONG
14773
    else:
14774
        dtype = DATATYPE.SHORT
14775

14776
    with TempFileName(
14777
        'write_bytecounts_{}{}{}{}{}'.format(
14778
            bigtiff, tiled, compression, count, bytecount
14779
        )
14780
    ) as fname:
14781
        imwrite(
14782
            fname,
14783
            data,
14784
            bigtiff=bigtiff,
14785
            tile=tile,
14786
            compression=COMPRESSION.ADOBE_DEFLATE if compression else None,
14787
            compressionargs={'level': compression} if compression else None,
14788
            rowsperstrip=rowsperstrip,
14789
        )
14790
        if not bigtiff:
14791
            assert_valid_tiff(fname)
14792
        with TiffFile(fname) as tif:
14793
            assert len(tif.pages) == 1
14794
            page = tif.pages.first
14795
            assert page.tags[tag].count == count
14796
            assert page.tags[tag].dtype == dtype
14797
            assert page.is_contiguous == is_contiguous
14798
            assert page.planarconfig == PLANARCONFIG.CONTIG
14799
            assert page.photometric == PHOTOMETRIC.MINISBLACK
14800
            assert page.imagewidth == shape[1]
14801
            assert page.imagelength == shape[0]
14802
            assert page.samplesperpixel == 1
14803
            assert_array_equal(page.asarray(), data)
14804
            assert_aszarr_method(page, data)
14805
            assert__str__(tif)
14806

14807

14808
@pytest.mark.skipif(SKIP_EXTENDED, reason=REASON)
14809
@pytest.mark.parametrize('repeat', [1, 4])
14810
@pytest.mark.parametrize('shape', [(1, 0), (0, 1), (3, 0, 2, 1)])
14811
@pytest.mark.parametrize('data', ['random', 'empty'])
14812
@pytest.mark.parametrize('shaped', [True, False])
14813
def test_write_zeroshape(shaped, data, repeat, shape):
14814
    """Test write arrays with zero shape."""
14815
    dtype = numpy.uint8
14816
    fname = 'write_shape_{}x{}{}{}'.format(
14817
        repeat,
14818
        str(shape).replace(' ', ''),
14819
        '_shaped' if shaped else '',
14820
        '_empty' if data == 'empty' else '',
14821
    )
14822
    metadata = {} if shaped else None
14823

14824
    with TempFileName(fname) as fname:
14825
        if data == 'empty':
14826
            with TiffWriter(fname) as tif:
14827
                with pytest.warns(UserWarning):
14828
                    for _ in range(repeat):
14829
                        tif.write(
14830
                            shape=shape,
14831
                            dtype=dtype,
14832
                            contiguous=True,
14833
                            metadata=metadata,
14834
                        )
14835
                    tif.write(numpy.zeros((16, 16), 'u2'), metadata=metadata)
14836
            with TiffFile(fname) as tif:
14837
                assert__str__(tif)
14838
                image = zimage = tif.asarray()
14839
                if not SKIP_ZARR:
14840
                    zimage = zarr.open(tif.aszarr(), mode='r')
14841
        else:
14842
            data = random_data(dtype, shape)
14843
            with TiffWriter(fname) as tif:
14844
                with pytest.warns(UserWarning):
14845
                    for _ in range(repeat):
14846
                        tif.write(data, contiguous=True, metadata=metadata)
14847
                    tif.write(numpy.zeros((16, 16), 'u2'), metadata=metadata)
14848
            with TiffFile(fname) as tif:
14849
                assert__str__(tif)
14850
                image = zimage = tif.asarray()
14851
                if not SKIP_ZARR:
14852
                    zimage = zarr.open(tif.aszarr(), mode='r')
14853

14854
            assert image.flags['C_CONTIGUOUS']
14855
            if shaped:
14856
                if repeat > 1:
14857
                    for i in range(repeat):
14858
                        assert_array_equal(image[i], data)
14859
                        assert_array_equal(zimage[i], data)
14860
                else:
14861
                    assert_array_equal(image, data)
14862
                    assert_array_equal(zimage, data)
14863
            else:
14864
                empty = numpy.empty((0, 0), dtype)
14865
                if repeat > 1:
14866
                    for i in range(repeat):
14867
                        assert_array_equal(image[i], empty)
14868
                        assert_array_equal(zimage[i], empty)
14869
                else:
14870
                    assert_array_equal(image.squeeze(), empty)
14871
                    # assert_array_equal(zimage.squeeze(), empty)
14872

14873
        if repeat > 1:
14874
            assert image.shape[0] == repeat
14875
            assert zimage.shape[0] == repeat
14876
        elif shaped:
14877
            assert shape == image.shape
14878
            assert shape == zimage.shape
14879
        else:
14880
            assert image.shape == (0, 0)
14881
            assert zimage.shape == (0, 0)
14882
        assert dtype == image.dtype
14883
        assert dtype == zimage.dtype
14884

14885

14886
@pytest.mark.parametrize('repeats', [1, 2])
14887
@pytest.mark.parametrize('series', [1, 2])
14888
@pytest.mark.parametrize('subifds', [0, 1, 2])
14889
@pytest.mark.parametrize('compressed', [False, True])
14890
@pytest.mark.parametrize('tiled', [False, True])
14891
@pytest.mark.parametrize('ome', [False, True])
14892
def test_write_subidfs(ome, tiled, compressed, series, repeats, subifds):
14893
    """Test write SubIFDs."""
14894
    # use BigTIFF to prevent Windows explorer from locking the file
14895
    if repeats > 1 and (compressed or tiled or ome):
14896
        pytest.xfail('contiguous not working with compression, tiles, ome')
14897

14898
    data = [
14899
        (numpy.random.rand(5, 64, 64) * 1023).astype(numpy.uint16),
14900
        (numpy.random.rand(5, 32, 32) * 1023).astype(numpy.uint16),
14901
        (numpy.random.rand(5, 16, 16) * 1023).astype(numpy.uint16),
14902
    ]
14903

14904
    kwargs = {
14905
        'tile': (16, 16) if tiled else None,
14906
        'compression': COMPRESSION.ADOBE_DEFLATE if compressed else None,
14907
        'compressionargs': {'level': 6} if compressed else None,
14908
    }
14909

14910
    with TempFileName(
14911
        'write_subidfs_'
14912
        f'{ome}-{tiled}-{compressed}-{subifds}-{series}-{repeats}'
14913
    ) as fname:
14914
        with TiffWriter(fname, ome=ome, bigtiff=True) as tif:
14915
            for _ in range(series):
14916
                for r in range(repeats):
14917
                    kwargs['contiguous'] = r != 0
14918
                    tif.write(data[0], subifds=subifds, **kwargs)
14919
                for i in range(1, subifds + 1):
14920
                    for r in range(repeats):
14921
                        kwargs['contiguous'] = r != 0
14922
                        tif.write(data[i], subfiletype=1, **kwargs)
14923

14924
        with TiffFile(fname) as tif:
14925
            for i, page in enumerate(tif.pages):
14926
                assert not page.is_subifd
14927
                if i % (5 * repeats):
14928
                    assert page.description == ''
14929
                elif ome:
14930
                    if i == 0:
14931
                        assert page.is_ome
14932
                    else:
14933
                        assert page.description == ''
14934
                else:
14935
                    assert page.is_shaped
14936

14937
                assert_array_equal(page.asarray(), data[0][i % 5])
14938
                assert_aszarr_method(page, data[0][i % 5])
14939
                if subifds:
14940
                    assert len(page.pages) == subifds
14941
                    for j, subifd in enumerate(page.pages):
14942
                        assert subifd.is_subifd
14943
                        assert_array_equal(
14944
                            subifd.asarray(), data[j + 1][i % 5]
14945
                        )
14946
                        assert_aszarr_method(subifd, data[j + 1][i % 5])
14947
                else:
14948
                    assert page.pages is None
14949

14950
            for i, page in enumerate(tif.pages[:-1]):
14951
                assert page._nextifd() == tif.pages[i + 1].offset
14952

14953
                if subifds:
14954
                    for j, subifd in enumerate(page.pages[:-1]):
14955
                        assert subifd.is_subifd
14956
                        assert subifd.subfiletype == FILETYPE.REDUCEDIMAGE
14957
                        assert subifd._nextifd() == page.subifds[j + 1]
14958
                    assert page.pages[-1]._nextifd() == 0
14959
                else:
14960
                    assert page.pages is None
14961

14962
            assert len(tif.series) == series
14963

14964
            if repeats > 1:
14965
                for s in range(series):
14966
                    assert tif.series[s].kind == 'ome' if ome else 'shaped'
14967
                    assert_array_equal(tif.series[s].asarray()[0], data[0])
14968
                    for i in range(subifds):
14969
                        assert_array_equal(
14970
                            tif.series[s].levels[i + 1].asarray()[0],
14971
                            data[i + 1],
14972
                        )
14973
            else:
14974
                for s in range(series):
14975
                    assert tif.series[s].kind == 'ome' if ome else 'shaped'
14976
                    assert_array_equal(tif.series[s].asarray(), data[0])
14977
                    for i in range(subifds):
14978
                        assert_array_equal(
14979
                            tif.series[s].levels[i + 1].asarray(), data[i + 1]
14980
                        )
14981

14982

14983
def test_write_lists():
14984
    """Test write lists."""
14985
    array = numpy.arange(1000).reshape(10, 10, 10).astype(numpy.uint16)
14986
    data = array.tolist()
14987
    with TempFileName('write_lists') as fname:
14988
        with TiffWriter(fname) as tif:
14989
            tif.write(data, dtype=numpy.uint16)
14990
            tif.write(data, compression=COMPRESSION.ADOBE_DEFLATE)
14991
            tif.write([100.0])
14992
            with pytest.warns(UserWarning):
14993
                tif.write([])
14994
        with TiffFile(fname) as tif:
14995
            assert_array_equal(tif.series[0].asarray(), array)
14996
            assert_array_equal(tif.series[1].asarray(), array)
14997
            assert_array_equal(tif.series[2].asarray(), [100.0])
14998
            assert_array_equal(tif.series[3].asarray(), [])
14999
            assert_aszarr_method(tif.series[0], array)
15000
            assert_aszarr_method(tif.series[1], array)
15001
            assert_aszarr_method(tif.series[2], [100.0])
15002
            # assert_aszarr_method(tif.series[3], [])
15003

15004

15005
def test_write_nopages():
15006
    """Test write TIFF with no pages."""
15007
    with TempFileName('write_nopages') as fname:
15008
        with TiffWriter(fname) as tif:
15009
            pass
15010
        with TiffFile(fname) as tif:
15011
            assert len(tif.pages) == 0
15012
            tif.asarray()
15013
        if not SKIP_VALIDATE:
15014
            with pytest.raises(ValueError):
15015
                assert_valid_tiff(fname)
15016

15017

15018
def test_write_append_not_exists():
15019
    """Test append to non existing file."""
15020
    with TempFileName('write_append_not_exists.bin') as fname:
15021
        # with self.assertRaises(ValueError):
15022
        with TiffWriter(fname, append=True):
15023
            pass
15024

15025

15026
def test_write_append_nontif():
15027
    """Test fail to append to non-TIFF file."""
15028
    with TempFileName('write_append_nontif.bin') as fname:
15029
        with open(fname, 'wb') as fh:
15030
            fh.write(b'not a TIFF file')
15031
        with pytest.raises(TiffFileError):
15032
            with TiffWriter(fname, append=True):
15033
                pass
15034

15035

15036
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
15037
def test_write_append_lsm():
15038
    """Test fail to append to LSM file."""
15039
    fname = private_file('lsm/take1.lsm')
15040
    with pytest.raises(ValueError):
15041
        with TiffWriter(fname, append=True):
15042
            pass
15043

15044

15045
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
15046
def test_write_append_create():
15047
    """Test append to non-existing file."""
15048
    with TempFileName('write_append_create') as fname:
15049
        if os.path.exists(fname):
15050
            os.remove(fname)
15051
        with TiffWriter(fname, append=True) as tif:
15052
            tif.write(shape=(31, 33), dtype=numpy.uint8)
15053
        data = imread(fname)
15054
    assert data.shape == (31, 33)
15055

15056

15057
def test_write_append_imwrite():
15058
    """Test append using imwrite."""
15059
    data = random_data(numpy.uint8, (21, 31))
15060
    with TempFileName('write_imwrite_append') as fname:
15061
        imwrite(fname, data, metadata=None)
15062
        for _ in range(3):
15063
            imwrite(fname, data, append=True, metadata=None)
15064
        a = imread(fname)
15065
        assert a.shape == (4, 21, 31)
15066
        assert_array_equal(a[3], data)
15067

15068

15069
def test_write_append():
15070
    """Test append to existing TIFF file."""
15071
    data = random_data(numpy.uint8, (21, 31))
15072
    with TempFileName('write_append') as fname:
15073
        with TiffWriter(fname) as tif:
15074
            pass
15075
        with TiffFile(fname) as tif:
15076
            assert len(tif.pages) == 0
15077
            assert__str__(tif)
15078

15079
        with TiffWriter(fname, append=True) as tif:
15080
            tif.write(data)
15081
        with TiffFile(fname) as tif:
15082
            assert len(tif.series) == 1
15083
            assert len(tif.pages) == 1
15084
            page = tif.pages.first
15085
            assert page.imagewidth == 31
15086
            assert page.imagelength == 21
15087
            assert__str__(tif)
15088

15089
        with TiffWriter(fname, append=True) as tif:
15090
            tif.write(data)
15091
            tif.write(data, contiguous=True)
15092
        with TiffFile(fname) as tif:
15093
            assert len(tif.series) == 2
15094
            assert len(tif.pages) == 3
15095
            page = tif.pages.first
15096
            assert page.imagewidth == 31
15097
            assert page.imagelength == 21
15098
            assert_array_equal(tif.asarray(series=1)[1], data)
15099
            assert__str__(tif)
15100

15101
        assert_valid_tiff(fname)
15102

15103

15104
def test_write_append_bytesio():
15105
    """Test append to existing TIFF file in BytesIO."""
15106
    data = random_data(numpy.uint8, (21, 31))
15107
    offset = 11
15108
    file = BytesIO()
15109
    file.write(b'a' * offset)
15110

15111
    with TiffWriter(file) as tif:
15112
        pass
15113
    file.seek(offset)
15114
    with TiffFile(file) as tif:
15115
        assert len(tif.pages) == 0
15116

15117
    file.seek(offset)
15118
    with TiffWriter(file, append=True) as tif:
15119
        tif.write(data)
15120
    file.seek(offset)
15121
    with TiffFile(file) as tif:
15122
        assert len(tif.series) == 1
15123
        assert len(tif.pages) == 1
15124
        page = tif.pages.first
15125
        assert page.imagewidth == 31
15126
        assert page.imagelength == 21
15127
        assert__str__(tif)
15128

15129
    file.seek(offset)
15130
    with TiffWriter(file, append=True) as tif:
15131
        tif.write(data)
15132
        tif.write(data, contiguous=True)
15133
    file.seek(offset)
15134
    with TiffFile(file) as tif:
15135
        assert len(tif.series) == 2
15136
        assert len(tif.pages) == 3
15137
        page = tif.pages.first
15138
        assert page.imagewidth == 31
15139
        assert page.imagelength == 21
15140
        assert_array_equal(tif.asarray(series=1)[1], data)
15141
        assert__str__(tif)
15142

15143

15144
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_CODECS, reason=REASON)
15145
def test_write_roundtrip_filename():
15146
    """Test write and read using file name."""
15147
    data = imread(public_file('tifffile/generic_series.tif'))
15148
    with TempFileName('write_roundtrip_filename') as fname:
15149
        imwrite(fname, data, photometric=PHOTOMETRIC.RGB)
15150
        assert_array_equal(imread(fname), data)
15151

15152

15153
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_CODECS, reason=REASON)
15154
def test_write_roundtrip_openfile():
15155
    """Test write and read using open file."""
15156
    pad = b'0' * 7
15157
    data = imread(public_file('tifffile/generic_series.tif'))
15158
    with TempFileName('write_roundtrip_openfile') as fname:
15159
        with open(fname, 'wb') as fh:
15160
            fh.write(pad)
15161
            imwrite(fh, data, photometric=PHOTOMETRIC.RGB)
15162
            fh.write(pad)
15163
        with open(fname, 'rb') as fh:
15164
            fh.seek(len(pad))
15165
            assert_array_equal(imread(fh), data)
15166

15167

15168
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_CODECS, reason=REASON)
15169
def test_write_roundtrip_bytesio():
15170
    """Test write and read using BytesIO."""
15171
    pad = b'0' * 7
15172
    data = imread(public_file('tifffile/generic_series.tif'))
15173
    buf = BytesIO()
15174
    buf.write(pad)
15175
    imwrite(buf, data, photometric=PHOTOMETRIC.RGB)
15176
    buf.write(pad)
15177
    buf.seek(len(pad))
15178
    assert_array_equal(imread(buf), data)
15179

15180

15181
def test_write_pages():
15182
    """Test write tags for contiguous data in all pages."""
15183
    data = random_data(numpy.float32, (17, 219, 301))
15184
    with TempFileName('write_pages') as fname:
15185
        imwrite(fname, data, photometric=PHOTOMETRIC.MINISBLACK)
15186
        assert_valid_tiff(fname)
15187
        # assert file
15188
        with TiffFile(fname) as tif:
15189
            assert len(tif.pages) == 17
15190
            for i, page in enumerate(tif.pages):
15191
                assert page.is_contiguous
15192
                assert page.planarconfig == PLANARCONFIG.CONTIG
15193
                assert page.photometric == PHOTOMETRIC.MINISBLACK
15194
                assert page.imagewidth == 301
15195
                assert page.imagelength == 219
15196
                assert page.samplesperpixel == 1
15197
                image = page.asarray()
15198
                assert_array_equal(data[i], image)
15199
            # assert series
15200
            series = tif.series[0]
15201
            assert series.kind == 'shaped'
15202
            assert series.dataoffset is not None
15203
            image = series.asarray()
15204
            assert_array_equal(data, image)
15205
            assert__str__(tif)
15206

15207

15208
def test_write_truncate():
15209
    """Test only one page is written for truncated files."""
15210
    shape = (4, 5, 6, 1)
15211
    with TempFileName('write_truncate') as fname:
15212
        imwrite(fname, random_data(numpy.uint8, shape), truncate=True)
15213
        assert_valid_tiff(fname)
15214
        with TiffFile(fname) as tif:
15215
            assert len(tif.pages) == 1  # not 4
15216
            page = tif.pages.first
15217
            assert page.is_shaped
15218
            assert page.shape == (5, 6)
15219
            assert '"shape": [4, 5, 6, 1]' in page.description
15220
            assert '"truncated": true' in page.description
15221
            series = tif.series[0]
15222
            assert series.is_truncated
15223
            assert series.kind == 'shaped'
15224
            assert series.shape == shape
15225
            assert len(series._pages) == 1
15226
            assert len(series.pages) == 1
15227
            data = tif.asarray()
15228
            assert data.shape == shape
15229
            assert_aszarr_method(tif, data)
15230
            assert_aszarr_method(tif, data, chunkmode='page')
15231
            assert__str__(tif)
15232

15233

15234
def test_write_is_shaped():
15235
    """Test files are written with shape."""
15236
    with TempFileName('write_is_shaped') as fname:
15237
        imwrite(
15238
            fname,
15239
            random_data(numpy.uint8, (4, 5, 6, 3)),
15240
            photometric=PHOTOMETRIC.RGB,
15241
        )
15242
        assert_valid_tiff(fname)
15243
        with TiffFile(fname) as tif:
15244
            assert len(tif.pages) == 4
15245
            page = tif.pages.first
15246
            assert page.is_shaped
15247
            assert page.description == '{"shape": [4, 5, 6, 3]}'
15248
            assert__str__(tif)
15249
    with TempFileName('write_is_shaped_with_description') as fname:
15250
        descr = 'test is_shaped_with_description'
15251
        imwrite(
15252
            fname,
15253
            random_data(numpy.uint8, (5, 6, 3)),
15254
            photometric=PHOTOMETRIC.RGB,
15255
            description=descr,
15256
        )
15257
        assert_valid_tiff(fname)
15258
        with TiffFile(fname) as tif:
15259
            assert len(tif.pages) == 1
15260
            page = tif.pages.first
15261
            assert page.is_shaped
15262
            assert page.description == descr
15263
            assert_aszarr_method(page)
15264
            assert_aszarr_method(page, chunkmode='page')
15265
            assert__str__(tif)
15266

15267

15268
def test_write_bytes_str():
15269
    """Test write bytes in place of 7-bit ascii string."""
15270
    micron = b'micron \xB5'  # can't be encoded as 7-bit ascii
15271
    data = numpy.arange(4, dtype=numpy.uint32).reshape((2, 2))
15272
    with TempFileName('write_bytes_str') as fname:
15273
        imwrite(
15274
            fname,
15275
            data,
15276
            description=micron,
15277
            software=micron,
15278
            extratags=[(50001, 's', 8, micron, True)],
15279
        )
15280
        with TiffFile(fname) as tif:
15281
            page = tif.pages.first
15282
            assert page.description == 'micron \xB5'
15283
            assert page.software == 'micron \xB5'
15284
            assert page.tags[50001].value == 'micron \xB5'
15285

15286

15287
def test_write_extratags():
15288
    """Test write extratags."""
15289
    data = random_data(numpy.uint8, (2, 219, 301))
15290
    description = 'Created by TestTiffWriter\nLorem ipsum dolor...'
15291
    pagename = 'Page name'
15292
    extratags = [
15293
        ('ImageDescription', 's', 0, description, True),
15294
        ('PageName', 's', 0, pagename, False),
15295
        (50001, 'b', 1, b'1', True),
15296
        (50002, 'b', 2, b'12', True),
15297
        (50004, 'b', 4, b'1234', True),
15298
        (50008, 'B', 8, b'12345678', True),
15299
    ]
15300
    with TempFileName('write_extratags') as fname:
15301
        imwrite(fname, data, extratags=extratags)
15302
        assert_valid_tiff(fname)
15303
        with TiffFile(fname) as tif:
15304
            assert len(tif.pages) == 2
15305
            assert tif.pages.first.description1 == description
15306
            assert 'ImageDescription' not in tif.pages[1].tags
15307
            assert tif.pages.first.tags['PageName'].value == pagename
15308
            assert tif.pages[1].tags['PageName'].value == pagename
15309
            assert '50001' not in tif.pages[1].tags
15310
            tags = tif.pages.first.tags
15311
            assert tags['50001'].value == 49
15312
            assert tags['50002'].value == (49, 50)
15313
            assert tags['50004'].value == (49, 50, 51, 52)
15314
            assert_array_equal(tags['50008'].value, b'12345678')
15315
            #                   (49, 50, 51, 52, 53, 54, 55, 56))
15316
            assert__str__(tif)
15317

15318

15319
def test_write_double_tags():
15320
    """Test write single and sequences of doubles."""
15321
    # older versions of tifffile do not use offset to write doubles
15322
    # reported by Eric Prestat on Feb 21, 2016
15323
    data = random_data(numpy.uint8, (8, 8))
15324
    value = math.pi
15325
    extratags = [
15326
        (34563, 'd', 1, value, False),
15327
        (34564, 'd', 1, (value,), False),
15328
        (34565, 'd', 2, (value, value), False),
15329
        (34566, 'd', 2, [value, value], False),
15330
        (34567, 'd', 2, numpy.array((value, value)), False),
15331
    ]
15332
    with TempFileName('write_double_tags') as fname:
15333
        imwrite(fname, data, extratags=extratags)
15334
        assert_valid_tiff(fname)
15335
        with TiffFile(fname) as tif:
15336
            assert len(tif.pages) == 1
15337
            tags = tif.pages.first.tags
15338
            assert tags['34563'].value == value
15339
            assert tags['34564'].value == value
15340
            assert tuple(tags['34565'].value) == (value, value)
15341
            assert tuple(tags['34566'].value) == (value, value)
15342
            assert tuple(tags['34567'].value) == (value, value)
15343
            assert__str__(tif)
15344

15345
    with TempFileName('write_double_tags_bigtiff') as fname:
15346
        imwrite(fname, data, bigtiff=True, extratags=extratags)
15347
        # assert_jhove(fname)
15348
        with TiffFile(fname) as tif:
15349
            assert len(tif.pages) == 1
15350
            tags = tif.pages.first.tags
15351
            assert tags['34563'].value == value
15352
            assert tags['34564'].value == value
15353
            assert tuple(tags['34565'].value) == (value, value)
15354
            assert tuple(tags['34566'].value) == (value, value)
15355
            assert tuple(tags['34567'].value) == (value, value)
15356
            assert__str__(tif)
15357

15358

15359
def test_write_short_tags():
15360
    """Test write single and sequences of words."""
15361
    data = random_data(numpy.uint8, (8, 8))
15362
    value = 65531
15363
    extratags = [
15364
        (34564, 'H', 1, (value,) * 1, False),
15365
        (34565, 'H', 2, (value,) * 2, False),
15366
        (34566, 'H', 3, (value,) * 3, False),
15367
        (34567, 'H', 4, (value,) * 4, False),
15368
    ]
15369
    with TempFileName('write_short_tags') as fname:
15370
        imwrite(fname, data, extratags=extratags)
15371
        assert_valid_tiff(fname)
15372
        with TiffFile(fname) as tif:
15373
            assert len(tif.pages) == 1
15374
            tags = tif.pages.first.tags
15375
            assert tags['34564'].value == value
15376
            assert tuple(tags['34565'].value) == (value,) * 2
15377
            assert tuple(tags['34566'].value) == (value,) * 3
15378
            assert tuple(tags['34567'].value) == (value,) * 4
15379
            assert__str__(tif)
15380

15381

15382
@pytest.mark.parametrize('subfiletype', [0b1, 0b10, 0b100, 0b1000, 0b1111])
15383
def test_write_subfiletype(subfiletype):
15384
    """Test write subfiletype."""
15385
    data = random_data(numpy.uint8, (16, 16))
15386
    if subfiletype & 0b100:
15387
        data = data.astype('bool')
15388
    with TempFileName(f'write_subfiletype_{subfiletype}') as fname:
15389
        imwrite(fname, data, subfiletype=subfiletype)
15390
        assert_valid_tiff(fname)
15391
        with TiffFile(fname) as tif:
15392
            page = tif.pages.first
15393
            assert page.subfiletype == subfiletype
15394
            assert page.is_reduced == bool(subfiletype & 0b1)
15395
            assert page.is_multipage == bool(subfiletype & 0b10)
15396
            assert page.is_mask == bool(subfiletype & 0b100)
15397
            assert page.is_mrc == bool(subfiletype & 0b1000)
15398
            assert_array_equal(data, page.asarray())
15399
            assert__str__(tif)
15400

15401

15402
@pytest.mark.parametrize('dt', [None, True, datetime, '2019:01:30 04:05:37'])
15403
def test_write_datetime_tag(dt):
15404
    """Test write datetime tag."""
15405
    arg = dt
15406
    if dt is datetime:
15407
        arg = datetime.datetime.now().replace(microsecond=0)
15408
    data = random_data(numpy.uint8, (31, 32))
15409
    with TempFileName('write_datetime') as fname:
15410
        imwrite(fname, data, datetime=arg)
15411
        with TiffFile(fname) as tif:
15412
            page = tif.pages.first
15413
            if dt is None:
15414
                assert 'DateTime' not in page.tags
15415
                assert page.datetime is None
15416
            elif dt is True:
15417
                dt = datetime.datetime.now().strftime('%Y:%m:%d %H:')
15418
                assert page.tags['DateTime'].value.startswith(dt)
15419
            elif dt is datetime:
15420
                assert page.tags['DateTime'].value == arg.strftime(
15421
                    '%Y:%m:%d %H:%M:%S'
15422
                )
15423
                assert page.datetime == arg
15424
            else:
15425
                assert page.tags['DateTime'].value == dt
15426
                assert page.datetime == datetime.datetime.strptime(
15427
                    dt, '%Y:%m:%d %H:%M:%S'
15428
                )
15429
            assert__str__(tif)
15430

15431

15432
def test_write_software_tag():
15433
    """Test write Software tag."""
15434
    data = random_data(numpy.uint8, (2, 219, 301))
15435
    software = 'test_tifffile.py'
15436
    with TempFileName('write_software_tag') as fname:
15437
        imwrite(fname, data, software=software)
15438
        assert_valid_tiff(fname)
15439
        with TiffFile(fname) as tif:
15440
            assert len(tif.pages) == 2
15441
            assert tif.pages.first.software == software
15442
            assert 'Software' not in tif.pages[1].tags
15443
            assert__str__(tif)
15444

15445

15446
def test_write_description_tag():
15447
    """Test write two description tags."""
15448
    data = random_data(numpy.uint8, (2, 219, 301))
15449
    description = 'Created by TestTiffWriter\nLorem ipsum dolor...'
15450
    with TempFileName('write_description_tag') as fname:
15451
        imwrite(fname, data, description=description)
15452
        assert_valid_tiff(fname)
15453
        with TiffFile(fname) as tif:
15454
            assert len(tif.pages) == 2
15455
            assert tif.pages.first.description == description
15456
            assert tif.pages.first.description1 == '{"shape": [2, 219, 301]}'
15457
            assert 'ImageDescription' not in tif.pages[1].tags
15458
            assert__str__(tif)
15459

15460

15461
def test_write_description_tag_nometadata():
15462
    """Test no JSON description is written with metatata=None."""
15463
    data = random_data(numpy.uint8, (2, 219, 301))
15464
    description = 'Created by TestTiffWriter\nLorem ipsum dolor...'
15465
    with TempFileName('write_description_tag_nometadatan') as fname:
15466
        imwrite(fname, data, description=description, metadata=None)
15467
        assert_valid_tiff(fname)
15468
        with TiffFile(fname) as tif:
15469
            assert len(tif.pages) == 2
15470
            assert tif.pages.first.description == description
15471
            assert 'ImageDescription' not in tif.pages[1].tags
15472
            assert (
15473
                tif.pages.first.tags.get('ImageDescription', index=1) is None
15474
            )
15475
            assert tif.series[0].kind == 'generic'
15476
            assert__str__(tif)
15477

15478

15479
def test_write_description_tag_notshaped():
15480
    """Test no JSON description is written with shaped=False."""
15481
    data = random_data(numpy.uint8, (2, 219, 301))
15482
    description = 'Created by TestTiffWriter\nLorem ipsum dolor...'
15483
    with TempFileName('write_description_tag_notshaped') as fname:
15484
        imwrite(fname, data, description=description, shaped=False)
15485
        assert_valid_tiff(fname)
15486
        with TiffFile(fname) as tif:
15487
            assert len(tif.pages) == 2
15488
            assert tif.pages.first.description == description
15489
            assert 'ImageDescription' not in tif.pages[1].tags
15490
            assert (
15491
                tif.pages.first.tags.get('ImageDescription', index=1) is None
15492
            )
15493
            assert tif.series[0].kind == 'generic'
15494
            assert__str__(tif)
15495

15496

15497
def test_write_description_ome():
15498
    """Test write multiple imagedescription tags to OME."""
15499
    # https://forum.image.sc/t/79471
15500
    with TempFileName('write_description_ome') as fname:
15501
        with pytest.warns(UserWarning):
15502
            imwrite(
15503
                fname,
15504
                shape=(2, 32, 32),
15505
                dtype=numpy.uint8,
15506
                ome=True,
15507
                description='description',  # not written
15508
                extratags=[('ImageDescription', 2, None, 'extratags', False)],
15509
            )
15510
        with TiffFile(fname) as tif:
15511
            assert tif.is_ome
15512
            page = tif.pages.first
15513
            assert page.description.startswith('<?xml')
15514
            assert page.description1 == 'extratags'
15515
            assert tif.pages[1].description == 'extratags'
15516

15517

15518
def test_write_description_imagej():
15519
    """Test write multiple imagedescription tags."""
15520
    with TempFileName('write_description_imagej') as fname:
15521
        with pytest.warns(UserWarning):
15522
            imwrite(
15523
                fname,
15524
                shape=(2, 32, 32),
15525
                dtype=numpy.uint8,
15526
                imagej=True,
15527
                description='description',  # not written
15528
                extratags=[('ImageDescription', 2, None, 'extratags', False)],
15529
            )
15530
        with TiffFile(fname) as tif:
15531
            assert tif.is_imagej
15532
            page = tif.pages.first
15533
            assert page.description.startswith('ImageJ=')
15534
            assert page.description1 == 'extratags'
15535
            assert tif.pages[1].description == 'extratags'
15536

15537

15538
def test_write_description_shaped():
15539
    """Test write multiple imagedescription tags to shaped."""
15540
    with TempFileName('write_description_shaped') as fname:
15541
        imwrite(
15542
            fname,
15543
            shape=(2, 32, 32),
15544
            dtype=numpy.uint8,
15545
            description='description',  # written
15546
            extratags=[('ImageDescription', 2, None, 'extratags', False)],
15547
        )
15548
        with TiffFile(fname) as tif:
15549
            assert tif.is_shaped
15550
            page = tif.pages.first
15551
            assert page.description == 'description'
15552
            assert page.description1.startswith('{')
15553
            assert page.tags.getall(270)[2].value == 'extratags'
15554
            assert tif.pages[1].description == 'extratags'
15555

15556

15557
def test_write_description_overwrite():
15558
    """Test overwrite imagedescription tag."""
15559
    with TempFileName('write_description_overwrite') as fname:
15560
        with TiffWriter(fname) as tif:
15561
            tif.write(
15562
                shape=(2, 32, 32),
15563
                dtype=numpy.uint8,
15564
                description='description',  # overwritten
15565
                extratags=[('ImageDescription', 2, None, 'extratags', False)],
15566
                metadata=None,
15567
            )
15568
            tif.overwrite_description('overwritten description')
15569
        with TiffFile(fname) as tif:
15570
            assert not tif.is_shaped
15571
            page = tif.pages.first
15572
            assert page.description == 'overwritten description'
15573
            assert page.description1 == 'extratags'
15574
            assert tif.pages[1].description == 'extratags'
15575

15576

15577
def test_write_description_extratags():
15578
    """Test write imagedescription tags using extratag."""
15579
    with TempFileName('write_description_extratags') as fname:
15580
        with TiffWriter(fname) as tif:
15581
            tif.write(
15582
                shape=(2, 32, 32),
15583
                dtype=numpy.uint8,
15584
                extratags=[
15585
                    (270, 2, None, 'description 0', False),
15586
                    ('ImageDescription', 2, None, 'description 1', False),
15587
                ],
15588
                metadata=None,
15589
            )
15590
        with TiffFile(fname) as tif:
15591
            assert not tif.is_shaped
15592
            page = tif.pages.first
15593
            assert page.description == 'description 0'
15594
            assert page.description1 == 'description 1'
15595
            page = tif.pages[1]
15596
            assert page.description == 'description 0'
15597
            assert page.description1 == 'description 1'
15598

15599

15600
def test_write_resolution_float():
15601
    """Test write float Resolution tag."""
15602
    data = random_data(numpy.uint8, (2, 219, 301))
15603
    resolution = (92.0, 92.0)
15604
    with TempFileName('write_resolution_float') as fname:
15605
        imwrite(fname, data, resolution=resolution)
15606
        assert_valid_tiff(fname)
15607
        with TiffFile(fname) as tif:
15608
            assert len(tif.pages) == 2
15609
            assert tif.pages.first.tags['XResolution'].value == (92, 1)
15610
            assert tif.pages.first.tags['YResolution'].value == (92, 1)
15611
            assert tif.pages.first.tags['ResolutionUnit'].value == 2
15612
            assert tif.pages[1].tags['XResolution'].value == (92, 1)
15613
            assert tif.pages[1].tags['YResolution'].value == (92, 1)
15614
            assert tif.pages.first.tags['ResolutionUnit'].value == 2
15615
            assert__str__(tif)
15616

15617

15618
def test_write_resolution_rational():
15619
    """Test write rational Resolution tag."""
15620
    data = random_data(numpy.uint8, (1, 219, 301))
15621
    resolution = ((300, 1), (300, 1))
15622
    with TempFileName('write_resolution_rational') as fname:
15623
        imwrite(fname, data, resolution=resolution, resolutionunit=1)
15624
        assert_valid_tiff(fname)
15625
        with TiffFile(fname) as tif:
15626
            assert len(tif.pages) == 1
15627
            assert tif.pages.first.tags['XResolution'].value == (300, 1)
15628
            assert tif.pages.first.tags['YResolution'].value == (300, 1)
15629
            assert tif.pages.first.tags['ResolutionUnit'].value == 1
15630

15631

15632
def test_write_resolution_unit():
15633
    """Test write Resolution tag unit."""
15634
    data = random_data(numpy.uint8, (219, 301))
15635
    resolution = (92.0, (9200, 100), 3)
15636
    with TempFileName('write_resolution_unit') as fname:
15637
        with pytest.warns(DeprecationWarning):
15638
            imwrite(fname, data, resolution=resolution)
15639
        assert_valid_tiff(fname)
15640
        with TiffFile(fname) as tif:
15641
            assert len(tif.pages) == 1
15642
            assert tif.pages.first.tags['XResolution'].value == (92, 1)
15643
            assert tif.pages.first.tags['YResolution'].value == (92, 1)
15644
            assert tif.pages.first.tags['ResolutionUnit'].value == 3
15645
            assert__str__(tif)
15646

15647

15648
@pytest.mark.skipif(SKIP_CODECS, reason=REASON)
15649
@pytest.mark.parametrize('bps', [1, 2, 7, 8])
15650
@pytest.mark.parametrize('dtype', [numpy.uint8, numpy.uint16, numpy.uint32])
15651
def test_write_bitspersample(bps, dtype):
15652
    """Test write with packints."""
15653
    dtype = numpy.dtype(dtype)
15654
    bps += (dtype.itemsize // 2) * 8
15655
    data = numpy.arange(256 * 256 * 3, dtype=dtype).reshape((256, 256, 3))
15656
    with TempFileName(f'write_bitspersample_{dtype.char}{bps}') as fname:
15657
        # TODO: enable all cases once imagecodecs.packints_encode works
15658
        if bps == dtype.itemsize * 8:
15659
            imwrite(
15660
                fname, data, bitspersample=bps, photometric=PHOTOMETRIC.RGB
15661
            )
15662
            assert_array_equal(imread(fname), data)
15663
        else:
15664
            with pytest.raises(NotImplementedError):
15665
                imwrite(
15666
                    fname, data, bitspersample=bps, photometric=PHOTOMETRIC.RGB
15667
                )
15668
                assert_array_equal(imread(fname), data)
15669

15670

15671
def test_write_bitspersample_fail():
15672
    """Test write with packints fails."""
15673
    data = numpy.arange(32 * 32 * 3, dtype=numpy.uint32).reshape((32, 32, 3))
15674
    with TempFileName('write_bitspersample_fail') as fname:
15675
        with TiffWriter(fname) as tif:
15676
            # not working with compression
15677
            with pytest.raises(ValueError):
15678
                tif.write(
15679
                    data.astype(numpy.uint8),
15680
                    bitspersample=4,
15681
                    compression=COMPRESSION.ADOBE_DEFLATE,
15682
                    photometric=PHOTOMETRIC.RGB,
15683
                )
15684
            # dtype.itemsize != bitspersample
15685
            for dtype in (
15686
                numpy.int8,
15687
                numpy.int16,
15688
                numpy.float32,
15689
                numpy.uint64,
15690
            ):
15691
                with pytest.raises(ValueError):
15692
                    tif.write(
15693
                        data.astype(dtype),
15694
                        bitspersample=4,
15695
                        photometric=PHOTOMETRIC.RGB,
15696
                    )
15697
            # bitspersample out of data range
15698
            for bps in (0, 9, 16, 32):
15699
                with pytest.raises(ValueError):
15700
                    tif.write(
15701
                        data.astype(numpy.uint8),
15702
                        bitspersample=bps,
15703
                        photometric=PHOTOMETRIC.RGB,
15704
                    )
15705
            for bps in (1, 8, 17, 32):
15706
                with pytest.raises(ValueError):
15707
                    tif.write(
15708
                        data.astype(numpy.uint16),
15709
                        bitspersample=bps,
15710
                        photometric=PHOTOMETRIC.RGB,
15711
                    )
15712
            for bps in (1, 8, 16, 33, 64):
15713
                with pytest.raises(ValueError):
15714
                    tif.write(
15715
                        data.astype(numpy.uint32),
15716
                        bitspersample=bps,
15717
                        photometric=PHOTOMETRIC.RGB,
15718
                    )
15719

15720

15721
@pytest.mark.parametrize('kind', ['enum', 'int', 'lower', 'upper'])
15722
def test_write_enum_parameters(kind):
15723
    """Test imwrite using different kind of enum"""
15724
    data = random_data(numpy.uint8, (2, 6, 219, 301))
15725
    with TempFileName(f'write_enum_parameters_{kind}') as fname:
15726
        if kind == 'enum':
15727
            imwrite(
15728
                fname,
15729
                data,
15730
                photometric=PHOTOMETRIC.RGB,
15731
                planarconfig=PLANARCONFIG.SEPARATE,
15732
                extrasamples=(
15733
                    EXTRASAMPLE.ASSOCALPHA,
15734
                    EXTRASAMPLE.UNSPECIFIED,
15735
                    EXTRASAMPLE.UNASSALPHA,
15736
                ),
15737
                compression=COMPRESSION.ADOBE_DEFLATE,
15738
                predictor=PREDICTOR.HORIZONTAL,
15739
            )
15740
        elif kind == 'int':
15741
            imwrite(
15742
                fname,
15743
                data,
15744
                photometric=2,
15745
                planarconfig=2,
15746
                extrasamples=(1, 0, 2),
15747
                compression=8,
15748
                predictor=2,
15749
            )
15750
        elif kind == 'upper':
15751
            imwrite(
15752
                fname,
15753
                data,
15754
                photometric='RGB',
15755
                planarconfig='SEPARATE',
15756
                extrasamples=('ASSOCALPHA', 'UNSPECIFIED', 'UNASSALPHA'),
15757
                compression='ADOBE_DEFLATE',
15758
                predictor='HORIZONTAL',
15759
            )
15760
        elif kind == 'lower':
15761
            imwrite(
15762
                fname,
15763
                data,
15764
                photometric='rgb',
15765
                planarconfig='separate',
15766
                extrasamples=('assocalpha', 'unspecified', 'unassalpha'),
15767
                compression='adobe_deflate',
15768
                predictor='horizontal',
15769
            )
15770
        with TiffFile(fname) as tif:
15771
            assert len(tif.pages) == 2
15772
            page = tif.pages.first
15773
            assert page.imagewidth == 301
15774
            assert page.imagelength == 219
15775
            assert page.samplesperpixel == 6
15776
            assert page.photometric == PHOTOMETRIC.RGB
15777
            assert page.planarconfig == PLANARCONFIG.SEPARATE
15778
            assert page.extrasamples == (
15779
                EXTRASAMPLE.ASSOCALPHA,
15780
                EXTRASAMPLE.UNSPECIFIED,
15781
                EXTRASAMPLE.UNASSALPHA,
15782
            )
15783
            assert page.compression == COMPRESSION.ADOBE_DEFLATE
15784
            assert page.predictor == PREDICTOR.HORIZONTAL
15785
            image = tif.asarray()
15786
            assert_array_equal(data, image)
15787
            assert_aszarr_method(tif, image)
15788
            assert__str__(tif)
15789

15790

15791
@pytest.mark.parametrize(
15792
    'args',
15793
    [
15794
        (0, 0),
15795
        (1, 1),
15796
        (2, COMPRESSION.NONE),
15797
        (3, COMPRESSION.ADOBE_DEFLATE),
15798
        (4, 'zlib'),
15799
        (5, 'zlib', 5),
15800
        (6, 'zlib', 5, {'out': None}),
15801
        (7, 'zlib', None, {'level': 5}),
15802
    ],
15803
)
15804
def test_write_compression_args(args, recwarn):
15805
    """Test compression parameter."""
15806
    i = args[0]
15807
    compressionargs = args[1:]
15808
    compressed = compressionargs[0] not in {0, 1, COMPRESSION.NONE}
15809
    if len(compressionargs) == 1:
15810
        compressionargs = compressionargs[0]
15811
    rowsperstrip = 100 if compressed else None
15812

15813
    data = WRITE_DATA
15814
    with TempFileName(f'write_compression_args_{i}') as fname:
15815
        # with pytest.warns(DeprecationWarning if i > 4 else None):
15816
        imwrite(
15817
            fname,
15818
            data,
15819
            compression=compressionargs,
15820
            photometric=PHOTOMETRIC.RGB,
15821
            rowsperstrip=rowsperstrip,
15822
        )
15823
        if i > 4:
15824
            assert len(recwarn) == 1
15825
            user_warning = recwarn.pop(DeprecationWarning)
15826
            assert issubclass(user_warning.category, DeprecationWarning)
15827
        assert_valid_tiff(fname)
15828
        with TiffFile(fname) as tif:
15829
            assert len(tif.pages) == 1
15830
            page = tif.pages.first
15831
            assert page.compression == (
15832
                COMPRESSION.ADOBE_DEFLATE if compressed else COMPRESSION.NONE
15833
            )
15834
            assert page.planarconfig == PLANARCONFIG.SEPARATE
15835
            assert page.photometric == PHOTOMETRIC.RGB
15836
            assert page.imagewidth == 301
15837
            assert page.imagelength == 219
15838
            assert page.samplesperpixel == 3
15839
            assert len(page.dataoffsets) == (9 if compressed else 3)
15840
            image = tif.asarray()
15841
            assert_array_equal(data, image)
15842
            assert__str__(tif)
15843

15844

15845
@pytest.mark.parametrize(
15846
    'args',
15847
    [
15848
        (0, 0),
15849
        (1, 5),
15850
        (2, COMPRESSION.ADOBE_DEFLATE),
15851
        (3, COMPRESSION.ADOBE_DEFLATE, 5),
15852
    ],
15853
)
15854
def test_write_compress_args(args):
15855
    """Test compress parameter no longer works in 2022.4.22."""
15856
    i = args[0]
15857
    compressargs = args[1:]
15858
    if len(compressargs) == 1:
15859
        compressargs = compressargs[0]
15860

15861
    data = WRITE_DATA
15862
    with TempFileName(f'write_compression_args_{i}') as fname:
15863
        with pytest.raises(TypeError):
15864
            imwrite(
15865
                fname, data, compress=compressargs, photometric=PHOTOMETRIC.RGB
15866
            )
15867

15868

15869
def test_write_compression_none():
15870
    """Test write compression=0."""
15871
    data = WRITE_DATA
15872
    with TempFileName('write_compression_none') as fname:
15873
        imwrite(fname, data, compression=0, photometric=PHOTOMETRIC.RGB)
15874
        assert_valid_tiff(fname)
15875
        with TiffFile(fname) as tif:
15876
            assert len(tif.pages) == 1
15877
            page = tif.pages.first
15878
            assert page.is_contiguous
15879
            assert page.compression == COMPRESSION.NONE
15880
            assert page.planarconfig == PLANARCONFIG.SEPARATE
15881
            assert page.photometric == PHOTOMETRIC.RGB
15882
            assert page.imagewidth == 301
15883
            assert page.imagelength == 219
15884
            assert page.samplesperpixel == 3
15885
            assert len(page.dataoffsets) == 3
15886
            image = tif.asarray()
15887
            assert_array_equal(data, image)
15888
            assert_aszarr_method(tif, image)
15889
            assert__str__(tif)
15890

15891

15892
# @pytest.mark.parametrize('optimize', [None, False, True])
15893
# @pytest.mark.parametrize('smoothing', [None, 10])
15894
@pytest.mark.skipif(
15895
    SKIP_PUBLIC or SKIP_CODECS or not imagecodecs.JPEG.available, reason=REASON
15896
)
15897
@pytest.mark.parametrize('subsampling', ['444', '422', '420', '411'])
15898
@pytest.mark.parametrize('dtype', [numpy.uint8, numpy.uint16])
15899
def test_write_compression_jpeg(dtype, subsampling):
15900
    """Test write JPEG compression with subsampling."""
15901
    dtype = numpy.dtype(dtype)
15902
    filename = f'write_compression_jpeg_{dtype}_{subsampling}'
15903
    subsampling, atol = {
15904
        '444': [(1, 1), 5],
15905
        '422': [(2, 1), 10],
15906
        '420': [(2, 2), 20],
15907
        '411': [(4, 1), 40],
15908
    }[subsampling]
15909
    data = numpy.load(public_file('tifffile/rgb.u1.npy')).astype(dtype)
15910
    data = data[:32, :16].copy()  # make divisible by subsamples
15911
    with TempFileName(filename) as fname:
15912
        imwrite(
15913
            fname,
15914
            data,
15915
            compression=COMPRESSION.JPEG,
15916
            compressionargs={'level': 99},
15917
            subsampling=subsampling,
15918
            photometric=PHOTOMETRIC.RGB,
15919
        )
15920
        assert_valid_tiff(fname)
15921
        with TiffFile(fname) as tif:
15922
            assert len(tif.pages) == 1
15923
            page = tif.pages.first
15924
            assert not page.is_contiguous
15925
            if subsampling[0] > 1:
15926
                assert page.is_subsampled
15927
                assert page.tags['YCbCrSubSampling'].value == subsampling
15928
            assert page.compression == COMPRESSION.JPEG
15929
            assert page.photometric == PHOTOMETRIC.YCBCR
15930
            assert page.imagewidth == data.shape[1]
15931
            assert page.imagelength == data.shape[0]
15932
            assert page.samplesperpixel == 3
15933
            image = tif.asarray()
15934
            assert_allclose(data, image, atol=atol)
15935
            assert_aszarr_method(tif, image)
15936
            assert__str__(tif)
15937

15938

15939
@pytest.mark.parametrize('dtype', [numpy.uint8, bool])
15940
def test_write_compression_deflate(dtype):
15941
    """Test write ZLIB compression."""
15942
    dtype = numpy.dtype(dtype)
15943
    data = WRITE_DATA.astype(dtype)
15944
    with TempFileName(f'write_compression_deflate_{dtype}') as fname:
15945
        imwrite(
15946
            fname,
15947
            data,
15948
            compression=COMPRESSION.DEFLATE,
15949
            compressionargs={'level': 6},
15950
            photometric=PHOTOMETRIC.RGB,
15951
            rowsperstrip=108,
15952
        )
15953
        assert_valid_tiff(fname)
15954
        with TiffFile(fname) as tif:
15955
            assert len(tif.pages) == 1
15956
            page = tif.pages.first
15957
            assert not page.is_contiguous
15958
            assert page.compression == COMPRESSION.DEFLATE
15959
            assert page.planarconfig == PLANARCONFIG.SEPARATE
15960
            assert page.photometric == PHOTOMETRIC.RGB
15961
            assert page.imagewidth == 301
15962
            assert page.imagelength == 219
15963
            assert page.samplesperpixel == 3
15964
            assert page.rowsperstrip == 108
15965
            assert len(page.dataoffsets) == 9
15966
            image = tif.asarray()
15967
            assert_array_equal(data, image)
15968
            assert_aszarr_method(tif, image)
15969
            assert__str__(tif)
15970

15971

15972
def test_write_compression_deflate_level():
15973
    """Test write ZLIB compression with level."""
15974
    data = WRITE_DATA
15975
    with TempFileName('write_compression_deflate_level') as fname:
15976
        imwrite(
15977
            fname,
15978
            data,
15979
            compression=COMPRESSION.ADOBE_DEFLATE,
15980
            compressionargs={'level': 9},
15981
            photometric=PHOTOMETRIC.RGB,
15982
        )
15983
        assert_valid_tiff(fname)
15984
        with TiffFile(fname) as tif:
15985
            assert len(tif.pages) == 1
15986
            page = tif.pages.first
15987
            assert not page.is_contiguous
15988
            assert page.compression == COMPRESSION.ADOBE_DEFLATE
15989
            assert page.planarconfig == PLANARCONFIG.SEPARATE
15990
            assert page.photometric == PHOTOMETRIC.RGB
15991
            assert page.imagewidth == 301
15992
            assert page.imagelength == 219
15993
            assert page.samplesperpixel == 3
15994
            image = tif.asarray()
15995
            assert_array_equal(data, image)
15996
            assert_aszarr_method(tif, image)
15997
            assert__str__(tif)
15998

15999

16000
@pytest.mark.parametrize('dtype', [numpy.uint8, bool])
16001
def test_write_compression_lzma(dtype):
16002
    """Test write LZMA compression."""
16003
    dtype = numpy.dtype(dtype)
16004
    data = WRITE_DATA.astype(dtype)
16005
    with TempFileName(f'write_compression_lzma_{dtype}') as fname:
16006
        imwrite(
16007
            fname,
16008
            data,
16009
            compression=COMPRESSION.LZMA,
16010
            photometric=PHOTOMETRIC.RGB,
16011
            rowsperstrip=108,
16012
        )
16013
        assert_valid_tiff(fname)
16014
        with TiffFile(fname) as tif:
16015
            assert len(tif.pages) == 1
16016
            page = tif.pages.first
16017
            assert not page.is_contiguous
16018
            assert page.compression == COMPRESSION.LZMA
16019
            assert page.planarconfig == PLANARCONFIG.SEPARATE
16020
            assert page.photometric == PHOTOMETRIC.RGB
16021
            assert page.imagewidth == 301
16022
            assert page.imagelength == 219
16023
            assert page.samplesperpixel == 3
16024
            assert page.rowsperstrip == 108
16025
            assert len(page.dataoffsets) == 9
16026
            image = tif.asarray()
16027
            assert_array_equal(data, image)
16028
            assert_aszarr_method(tif, image)
16029
            assert__str__(tif)
16030

16031

16032
@pytest.mark.skipif(
16033
    SKIP_CODECS or not imagecodecs.ZSTD.available, reason=REASON
16034
)
16035
@pytest.mark.parametrize('dtype', [numpy.uint8, bool])
16036
def test_write_compression_zstd(dtype):
16037
    """Test write ZSTD compression."""
16038
    dtype = numpy.dtype(dtype)
16039
    data = WRITE_DATA.astype(dtype)
16040
    with TempFileName(f'write_compression_zstd_{dtype}') as fname:
16041
        imwrite(
16042
            fname,
16043
            data,
16044
            compression=COMPRESSION.ZSTD,
16045
            photometric=PHOTOMETRIC.RGB,
16046
            rowsperstrip=108,
16047
        )
16048
        assert_valid_tiff(fname)
16049
        with TiffFile(fname) as tif:
16050
            assert len(tif.pages) == 1
16051
            page = tif.pages.first
16052
            assert not page.is_contiguous
16053
            assert page.compression == COMPRESSION.ZSTD
16054
            assert page.planarconfig == PLANARCONFIG.SEPARATE
16055
            assert page.photometric == PHOTOMETRIC.RGB
16056
            assert page.imagewidth == 301
16057
            assert page.imagelength == 219
16058
            assert page.samplesperpixel == 3
16059
            assert page.rowsperstrip == 108
16060
            assert len(page.dataoffsets) == 9
16061
            image = tif.asarray()
16062
            assert_array_equal(data, image)
16063
            assert_aszarr_method(tif, image)
16064
            assert__str__(tif)
16065

16066

16067
@pytest.mark.skipif(
16068
    SKIP_CODECS or not imagecodecs.WEBP.available, reason=REASON
16069
)
16070
def test_write_compression_webp():
16071
    """Test write WEBP compression."""
16072
    data = WRITE_DATA.astype(numpy.uint8).reshape((219, 301, 3))
16073
    with TempFileName('write_compression_webp') as fname:
16074
        imwrite(
16075
            fname,
16076
            data,
16077
            compression=COMPRESSION.WEBP,
16078
            compressionargs={'level': -1},
16079
            photometric=PHOTOMETRIC.RGB,
16080
        )
16081
        assert_valid_tiff(fname)
16082
        with TiffFile(fname) as tif:
16083
            assert len(tif.pages) == 1
16084
            page = tif.pages.first
16085
            assert not page.is_contiguous
16086
            assert page.compression == COMPRESSION.WEBP
16087
            assert page.photometric == PHOTOMETRIC.RGB
16088
            assert page.imagewidth == 301
16089
            assert page.imagelength == 219
16090
            assert page.samplesperpixel == 3
16091
            image = tif.asarray()
16092
            assert_array_equal(data, image)
16093
            assert_aszarr_method(tif, image)
16094
            assert__str__(tif)
16095

16096

16097
@pytest.mark.skipif(
16098
    SKIP_CODECS or not imagecodecs.JPEG2K.available, reason=REASON
16099
)
16100
def test_write_compression_jpeg2k():
16101
    """Test write JPEG 2000 compression."""
16102
    data = WRITE_DATA.astype(numpy.uint8).reshape((219, 301, 3))
16103
    with TempFileName('write_compression_jpeg2k') as fname:
16104
        imwrite(
16105
            fname,
16106
            data,
16107
            compression=COMPRESSION.JPEG2000,
16108
            compressionargs={'level': -1},
16109
            photometric=PHOTOMETRIC.RGB,
16110
        )
16111
        assert_valid_tiff(fname)
16112
        with TiffFile(fname) as tif:
16113
            assert len(tif.pages) == 1
16114
            page = tif.pages.first
16115
            assert not page.is_contiguous
16116
            assert page.compression == COMPRESSION.JPEG2000
16117
            assert page.photometric == PHOTOMETRIC.RGB
16118
            assert page.imagewidth == 301
16119
            assert page.imagelength == 219
16120
            assert page.samplesperpixel == 3
16121
            image = tif.asarray()
16122
            assert_array_equal(data, image)
16123
            assert_aszarr_method(tif, image)
16124
            assert__str__(tif)
16125

16126

16127
@pytest.mark.skipif(
16128
    SKIP_CODECS or not imagecodecs.JPEGXL.available, reason=REASON
16129
)
16130
def test_write_compression_jpegxl():
16131
    """Test write JPEG XL compression."""
16132
    data = WRITE_DATA.astype(numpy.uint8).reshape((219, 301, 3))
16133
    with TempFileName('write_compression_jpegxl') as fname:
16134
        imwrite(
16135
            fname,
16136
            data,
16137
            compression=COMPRESSION.JPEGXL,
16138
            compressionargs={'level': 101},  # lossless
16139
            photometric=PHOTOMETRIC.RGB,
16140
        )
16141
        assert_valid_tiff(fname)
16142
        with TiffFile(fname) as tif:
16143
            assert len(tif.pages) == 1
16144
            page = tif.pages.first
16145
            assert not page.is_contiguous
16146
            assert page.compression == COMPRESSION.JPEGXL
16147
            assert page.photometric == PHOTOMETRIC.RGB
16148
            assert page.imagewidth == 301
16149
            assert page.imagelength == 219
16150
            assert page.samplesperpixel == 3
16151
            image = tif.asarray()
16152
            assert_array_equal(data, image)
16153
            assert_aszarr_method(tif, image)
16154
            assert__str__(tif)
16155

16156

16157
@pytest.mark.skipif(SKIP_CODECS, reason=REASON)
16158
@pytest.mark.parametrize('compression', [None, 'deflate', 'zstd'])
16159
def test_write_compression_lerc(compression):
16160
    """Test write LERC compression."""
16161
    if not hasattr(imagecodecs, 'LERC'):
16162
        pytest.skip('LERC codec missing')
16163
    compressionargs = {
16164
        None: None,
16165
        'deflate': {'level': 7},
16166
        'zstd': {'level': 10},
16167
    }[compression]
16168
    lercparameters = {
16169
        None: (4, 0),
16170
        'deflate': (4, 1),
16171
        'zstd': (4, 2),
16172
    }[compression]
16173

16174
    data = WRITE_DATA.astype(numpy.uint16).reshape((219, 301, 3))
16175
    with TempFileName(f'write_compression_lerc_{compression}') as fname:
16176
        imwrite(
16177
            fname,
16178
            data,
16179
            photometric=PHOTOMETRIC.RGB,
16180
            compression=COMPRESSION.LERC,
16181
            compressionargs={
16182
                'compression': compression,
16183
                'compressionargs': compressionargs,
16184
            },
16185
        )
16186
        assert_valid_tiff(fname)
16187
        with TiffFile(fname) as tif:
16188
            assert len(tif.pages) == 1
16189
            page = tif.pages.first
16190
            assert not page.is_contiguous
16191
            assert page.compression == COMPRESSION.LERC
16192
            assert page.photometric == PHOTOMETRIC.RGB
16193
            assert page.imagewidth == 301
16194
            assert page.imagelength == 219
16195
            assert page.samplesperpixel == 3
16196
            assert page.tags['LercParameters'].value == lercparameters
16197

16198
            image = tif.asarray()
16199
            assert_array_equal(data, image)
16200
            assert_aszarr_method(tif, image)
16201
            assert__str__(tif)
16202

16203

16204
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_CODECS, reason=REASON)
16205
def test_write_compression_jetraw():
16206
    """Test write Jetraw compression."""
16207
    try:
16208
        have_jetraw = imagecodecs.JETRAW.available
16209
    except AttributeError:
16210
        # requires imagecodecs > 2022.22.2
16211
        have_jetraw = False
16212
    if not have_jetraw:
16213
        pytest.skip('Jetraw codec not available')
16214

16215
    data = imread(private_file('jetraw/16ms-1.tif'))
16216
    assert data.dtype == numpy.uint16
16217
    assert data.shape == (2304, 2304)
16218
    assert data[1490, 1830] == 36701
16219

16220
    # Jetraw requires initialization
16221
    imagecodecs.jetraw_init()
16222

16223
    with TempFileName('write_compression_jetraw') as fname:
16224
        try:
16225
            imwrite(
16226
                fname,
16227
                data,
16228
                compression=COMPRESSION.JETRAW,
16229
                compressionargs={'identifier': '500202_standard_bin1x'},
16230
            )
16231
        except imagecodecs.JetrawError as exc:
16232
            if 'license' in str(exc):
16233
                pytest.skip('Jetraw_encode requires a license')
16234
            else:
16235
                raise exc
16236

16237
        with TiffFile(fname) as tif:
16238
            assert len(tif.pages) == 1
16239
            page = tif.pages.first
16240
            assert page.compression == COMPRESSION.JETRAW
16241
            assert page.photometric == PHOTOMETRIC.MINISBLACK
16242
            assert page.planarconfig == PLANARCONFIG.CONTIG
16243
            assert page.imagewidth == 2304
16244
            assert page.imagelength == 2304
16245
            assert page.rowsperstrip == 2304
16246
            assert page.bitspersample == 16
16247
            assert page.samplesperpixel == 1
16248
            image = tif.asarray()
16249
            assert 0.5 > numpy.mean(
16250
                image.astype(numpy.float32) - data.astype(numpy.float32)
16251
            )
16252
            assert__str__(tif)
16253

16254

16255
@pytest.mark.skipif(SKIP_CODECS, reason=REASON)
16256
@pytest.mark.parametrize('dtype', [numpy.int8, numpy.uint8, bool])
16257
@pytest.mark.parametrize('tile', [None, (16, 16)])
16258
def test_write_compression_packbits(dtype, tile):
16259
    """Test write PackBits compression."""
16260
    dtype = numpy.dtype(dtype)
16261
    uncompressed = numpy.frombuffer(
16262
        b'\xaa\xaa\xaa\x80\x00\x2a\xaa\xaa\xaa\xaa\x80\x00'
16263
        b'\x2a\x22\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa',
16264
        dtype=dtype,
16265
    )
16266
    shape = 2, 7, uncompressed.size
16267
    data = numpy.empty(shape, dtype=dtype)
16268
    data[..., :] = uncompressed
16269
    with TempFileName(f'write_compression_packits_{dtype}') as fname:
16270
        imwrite(fname, data, compression=COMPRESSION.PACKBITS, tile=tile)
16271
        assert_valid_tiff(fname)
16272
        with TiffFile(fname) as tif:
16273
            assert len(tif.pages) == 2
16274
            page = tif.pages.first
16275
            assert not page.is_contiguous
16276
            assert page.compression == COMPRESSION.PACKBITS
16277
            assert page.planarconfig == PLANARCONFIG.CONTIG
16278
            assert page.imagewidth == uncompressed.size
16279
            assert page.imagelength == 7
16280
            assert page.samplesperpixel == 1
16281
            image = tif.asarray()
16282
            assert_array_equal(data, image)
16283
            assert_aszarr_method(tif, image)
16284
            assert__str__(tif)
16285

16286

16287
def test_write_compression_rowsperstrip():
16288
    """Test write rowsperstrip with compression."""
16289
    data = WRITE_DATA
16290
    with TempFileName('write_compression_rowsperstrip') as fname:
16291
        imwrite(
16292
            fname,
16293
            data,
16294
            compression=COMPRESSION.ADOBE_DEFLATE,
16295
            rowsperstrip=32,
16296
            photometric=PHOTOMETRIC.RGB,
16297
        )
16298
        assert_valid_tiff(fname)
16299
        with TiffFile(fname) as tif:
16300
            assert len(tif.pages) == 1
16301
            page = tif.pages.first
16302
            assert not page.is_contiguous
16303
            assert page.compression == COMPRESSION.ADOBE_DEFLATE
16304
            assert page.planarconfig == PLANARCONFIG.SEPARATE
16305
            assert page.photometric == PHOTOMETRIC.RGB
16306
            assert page.imagewidth == 301
16307
            assert page.imagelength == 219
16308
            assert page.samplesperpixel == 3
16309
            assert page.rowsperstrip == 32
16310
            assert len(page.dataoffsets) == 21
16311
            image = tif.asarray()
16312
            assert_array_equal(data, image)
16313
            assert_aszarr_method(tif, image)
16314
            assert__str__(tif)
16315

16316

16317
def test_write_compression_tiled():
16318
    """Test write compressed tiles."""
16319
    data = WRITE_DATA
16320
    with TempFileName('write_compression_tiled') as fname:
16321
        imwrite(
16322
            fname,
16323
            data,
16324
            compression=COMPRESSION.ADOBE_DEFLATE,
16325
            tile=(32, 32),
16326
            photometric=PHOTOMETRIC.RGB,
16327
        )
16328
        assert_valid_tiff(fname)
16329
        with TiffFile(fname) as tif:
16330
            assert len(tif.pages) == 1
16331
            page = tif.pages.first
16332
            assert not page.is_contiguous
16333
            assert page.is_tiled
16334
            assert page.compression == COMPRESSION.ADOBE_DEFLATE
16335
            assert page.planarconfig == PLANARCONFIG.SEPARATE
16336
            assert page.photometric == PHOTOMETRIC.RGB
16337
            assert page.imagewidth == 301
16338
            assert page.imagelength == 219
16339
            assert page.samplesperpixel == 3
16340
            assert len(page.dataoffsets) == 210
16341
            image = tif.asarray()
16342
            assert_array_equal(data, image)
16343
            assert_aszarr_method(tif, image)
16344
            assert__str__(tif)
16345

16346

16347
def test_write_compression_predictor():
16348
    """Test write horizontal differencing."""
16349
    data = WRITE_DATA
16350
    with TempFileName('write_compression_predictor') as fname:
16351
        imwrite(
16352
            fname,
16353
            data,
16354
            compression=COMPRESSION.ADOBE_DEFLATE,
16355
            predictor=PREDICTOR.HORIZONTAL,
16356
            photometric=PHOTOMETRIC.RGB,
16357
        )
16358
        assert_valid_tiff(fname)
16359
        with TiffFile(fname) as tif:
16360
            assert len(tif.pages) == 1
16361
            page = tif.pages.first
16362
            assert not page.is_contiguous
16363
            assert page.compression == COMPRESSION.ADOBE_DEFLATE
16364
            assert page.planarconfig == PLANARCONFIG.SEPARATE
16365
            assert page.photometric == PHOTOMETRIC.RGB
16366
            assert page.predictor == PREDICTOR.HORIZONTAL
16367
            assert page.imagewidth == 301
16368
            assert page.imagelength == 219
16369
            assert page.samplesperpixel == 3
16370
            image = tif.asarray()
16371
            assert_array_equal(data, image)
16372
            assert_aszarr_method(tif, image)
16373
            assert__str__(tif)
16374

16375

16376
@pytest.mark.skipif(SKIP_CODECS, reason=REASON)
16377
@pytest.mark.parametrize('dtype', [numpy.uint16, numpy.float32])
16378
def test_write_compression_predictor_tiled(dtype):
16379
    """Test write horizontal differencing with tiles."""
16380
    dtype = numpy.dtype(dtype)
16381
    data = WRITE_DATA.astype(dtype)
16382
    with TempFileName(f'write_compression_tiled_predictor_{dtype}') as fname:
16383
        imwrite(
16384
            fname,
16385
            data,
16386
            compression=COMPRESSION.ADOBE_DEFLATE,
16387
            predictor=True,
16388
            tile=(32, 32),
16389
            photometric=PHOTOMETRIC.RGB,
16390
        )
16391
        if dtype.kind != 'f':
16392
            assert_valid_tiff(fname)
16393
        with TiffFile(fname) as tif:
16394
            assert len(tif.pages) == 1
16395
            page = tif.pages.first
16396
            assert not page.is_contiguous
16397
            assert page.is_tiled
16398
            assert page.compression == COMPRESSION.ADOBE_DEFLATE
16399
            assert page.planarconfig == PLANARCONFIG.SEPARATE
16400
            assert page.photometric == PHOTOMETRIC.RGB
16401
            assert page.imagewidth == 301
16402
            assert page.imagelength == 219
16403
            assert page.samplesperpixel == 3
16404
            assert page.predictor == 3 if dtype.kind == 'f' else 2
16405
            image = tif.asarray()
16406
            assert_array_equal(data, image)
16407
            assert_aszarr_method(tif, image)
16408
            assert__str__(tif)
16409

16410

16411
def test_write_rowsperstrip():
16412
    """Test write rowsperstrip without compression."""
16413
    data = WRITE_DATA
16414
    with TempFileName('write_rowsperstrip') as fname:
16415
        imwrite(
16416
            fname,
16417
            data,
16418
            rowsperstrip=32,
16419
            contiguous=False,
16420
            photometric=PHOTOMETRIC.RGB,
16421
            metadata=None,
16422
        )
16423
        assert_valid_tiff(fname)
16424
        with TiffFile(fname) as tif:
16425
            assert len(tif.pages) == 1
16426
            page = tif.pages.first
16427
            assert page.is_contiguous
16428
            assert page.planarconfig == PLANARCONFIG.SEPARATE
16429
            assert page.photometric == PHOTOMETRIC.RGB
16430
            assert page.imagewidth == 301
16431
            assert page.imagelength == 219
16432
            assert page.samplesperpixel == 3
16433
            assert page.rowsperstrip == 32
16434
            assert len(page.dataoffsets) == 21
16435
            stripbytecounts = page.tags['StripByteCounts'].value
16436
            assert stripbytecounts[0] == 19264
16437
            assert stripbytecounts[6] == 16254
16438
            image = tif.asarray()
16439
            assert_array_equal(data, image)
16440
            assert_aszarr_method(tif, image)
16441
            assert__str__(tif)
16442

16443

16444
@pytest.mark.skipif(IS_BE, reason=REASON)
16445
def test_write_bigendian():
16446
    """Test write big endian file."""
16447
    # also test memory mapping non-native byte order
16448
    data = random_data(numpy.float32, (2, 3, 219, 301))
16449
    data = data.view(data.dtype.newbyteorder())
16450
    data = numpy.nan_to_num(data, copy=False)
16451
    with TempFileName('write_bigendian') as fname:
16452
        imwrite(
16453
            fname,
16454
            data,
16455
            planarconfig=PLANARCONFIG.SEPARATE,
16456
            photometric=PHOTOMETRIC.RGB,
16457
        )
16458
        assert_valid_tiff(fname)
16459
        with TiffFile(fname) as tif:
16460
            assert len(tif.pages) == 2
16461
            assert len(tif.series) == 1
16462
            assert tif.byteorder == '>'
16463
            # assert not tif.isnative
16464
            assert tif.series[0].dataoffset is not None
16465
            page = tif.pages.first
16466
            assert page.is_contiguous
16467
            assert page.planarconfig == PLANARCONFIG.SEPARATE
16468
            assert page.photometric == PHOTOMETRIC.RGB
16469
            assert page.imagewidth == 301
16470
            assert page.imagelength == 219
16471
            assert page.samplesperpixel == 3
16472
            # test read data
16473
            image = tif.asarray()
16474
            assert_array_equal(data, image)
16475
            assert_aszarr_method(tif, image)
16476
            image = page.asarray()
16477
            assert_array_equal(data[0], image)
16478
            # test direct memory mapping; returns big endian array
16479
            image = tif.asarray(out='memmap')
16480
            assert isinstance(image, numpy.memmap)
16481
            assert image.dtype == numpy.dtype('>f4')
16482
            assert_array_equal(data, image)
16483
            del image
16484
            image = page.asarray(out='memmap')
16485
            assert isinstance(image, numpy.memmap)
16486
            assert image.dtype == numpy.dtype('>f4')
16487
            assert_array_equal(data[0], image)
16488
            del image
16489
            # test indirect memory mapping; returns native endian array
16490
            image = tif.asarray(out='memmap:')
16491
            assert isinstance(image, numpy.memmap)
16492
            assert image.dtype == numpy.dtype('=f4')
16493
            assert_array_equal(data, image)
16494
            del image
16495
            image = page.asarray(out='memmap:')
16496
            assert isinstance(image, numpy.memmap)
16497
            assert image.dtype == numpy.dtype('=f4')
16498
            assert_array_equal(data[0], image)
16499
            del image
16500
            # test 2nd page
16501
            page = tif.pages[1]
16502
            image = page.asarray(out='memmap')
16503
            assert isinstance(image, numpy.memmap)
16504
            assert image.dtype == numpy.dtype('>f4')
16505
            assert_array_equal(data[1], image)
16506
            del image
16507
            image = page.asarray(out='memmap:')
16508
            assert isinstance(image, numpy.memmap)
16509
            assert image.dtype == numpy.dtype('=f4')
16510
            assert_array_equal(data[1], image)
16511
            del image
16512
            assert__str__(tif)
16513

16514

16515
def test_write_zero_size():
16516
    """Test write zero size array no longer fails."""
16517
    # with pytest.raises(ValueError):
16518
    with pytest.warns(UserWarning):
16519
        with TempFileName('write_empty') as fname:
16520
            imwrite(fname, numpy.empty(0))
16521

16522

16523
def test_write_pixel():
16524
    """Test write single pixel."""
16525
    data = numpy.zeros(1, dtype=numpy.uint8)
16526
    with TempFileName('write_pixel') as fname:
16527
        imwrite(fname, data)
16528
        assert_valid_tiff(fname)
16529
        with TiffFile(fname) as tif:
16530
            assert len(tif.pages) == 1
16531
            assert tif.series[0].axes == 'Y'
16532
            page = tif.pages.first
16533
            assert page.is_contiguous
16534
            assert page.planarconfig == PLANARCONFIG.CONTIG
16535
            assert page.photometric != PHOTOMETRIC.RGB
16536
            assert page.imagewidth == 1
16537
            assert page.imagelength == 1
16538
            assert page.samplesperpixel == 1
16539
            image = tif.asarray()
16540
            assert_array_equal(data, image)
16541
            assert_aszarr_method(tif, image)
16542
            assert_aszarr_method(tif, image, chunkmode='page')
16543
            assert__str__(tif)
16544

16545

16546
def test_write_small():
16547
    """Test write small image."""
16548
    data = random_data(numpy.uint8, (1, 1))
16549
    with TempFileName('write_small') as fname:
16550
        imwrite(fname, data)
16551
        assert_valid_tiff(fname)
16552
        with TiffFile(fname) as tif:
16553
            assert len(tif.pages) == 1
16554
            page = tif.pages.first
16555
            assert page.is_contiguous
16556
            assert page.planarconfig == PLANARCONFIG.CONTIG
16557
            assert page.photometric != PHOTOMETRIC.RGB
16558
            assert page.imagewidth == 1
16559
            assert page.imagelength == 1
16560
            assert page.samplesperpixel == 1
16561
            image = tif.asarray()
16562
            assert_array_equal(data, image)
16563
            assert_aszarr_method(tif, image)
16564
            assert__str__(tif)
16565

16566

16567
def test_write_2d_as_rgb():
16568
    """Test write RGB color palette as RGB image."""
16569
    # image length should be 1
16570
    data = numpy.arange(3 * 256, dtype=numpy.uint16).reshape(256, 3) // 3
16571
    with TempFileName('write_2d_as_rgb_contig') as fname:
16572
        imwrite(fname, data, photometric=PHOTOMETRIC.RGB)
16573
        assert_valid_tiff(fname)
16574
        with TiffFile(fname) as tif:
16575
            assert len(tif.pages) == 1
16576
            assert tif.series[0].axes == 'XS'
16577
            page = tif.pages.first
16578
            assert page.is_contiguous
16579
            assert page.planarconfig == PLANARCONFIG.CONTIG
16580
            assert page.photometric == PHOTOMETRIC.RGB
16581
            assert page.imagewidth == 256
16582
            assert page.imagelength == 1
16583
            assert page.samplesperpixel == 3
16584
            image = tif.asarray()
16585
            assert_array_equal(data, image)
16586
            assert_aszarr_method(tif, image)
16587
            assert_aszarr_method(tif, image, chunkmode='page')
16588
            assert__str__(tif)
16589

16590

16591
def test_write_auto_photometric_planar():
16592
    """Test detect photometric in planar mode."""
16593
    data = random_data(numpy.uint8, (4, 31, 33))
16594
    with TempFileName('write_auto_photometric_planar1') as fname:
16595
        with pytest.warns(DeprecationWarning):
16596
            imwrite(fname, data)
16597
        assert_valid_tiff(fname)
16598
        with TiffFile(fname) as tif:
16599
            assert len(tif.pages) == 1
16600
            page = tif.pages.first
16601
            assert page.shape == (4, 31, 33)
16602
            assert page.axes == 'SYX'
16603
            assert page.planarconfig == PLANARCONFIG.SEPARATE
16604
            assert page.photometric == PHOTOMETRIC.RGB
16605
            assert len(page.extrasamples) == 1
16606

16607
    with TempFileName('write_auto_photometric_planar2') as fname:
16608
        with pytest.warns(DeprecationWarning):
16609
            imwrite(fname, data, planarconfig='separate')
16610
        assert_valid_tiff(fname)
16611
        with TiffFile(fname) as tif:
16612
            assert len(tif.pages) == 1
16613
            page = tif.pages.first
16614
            assert page.shape == (4, 31, 33)
16615
            assert page.axes == 'SYX'
16616
            assert page.planarconfig == PLANARCONFIG.SEPARATE
16617
            assert page.photometric == PHOTOMETRIC.RGB
16618
            assert len(page.extrasamples) == 1
16619

16620
    data = random_data(numpy.uint8, (4, 7, 31, 33))
16621
    with TempFileName('write_auto_photometric_volumetric_planar1') as fname:
16622
        with pytest.warns(DeprecationWarning):
16623
            imwrite(fname, data, volumetric=True)
16624
        assert_valid_tiff(fname)
16625
        with TiffFile(fname) as tif:
16626
            assert len(tif.pages) == 1
16627
            page = tif.pages.first
16628
            assert page.shape == (4, 7, 31, 33)
16629
            assert page.axes == 'SZYX'
16630
            assert page.planarconfig == PLANARCONFIG.SEPARATE
16631
            assert page.photometric == PHOTOMETRIC.RGB
16632
            assert len(page.extrasamples) == 1
16633
            assert page.is_volumetric
16634

16635
    with TempFileName('write_auto_photometric_volumetric_planar2') as fname:
16636
        with pytest.warns(DeprecationWarning):
16637
            imwrite(fname, data, planarconfig='separate', volumetric=True)
16638
        assert_valid_tiff(fname)
16639
        with TiffFile(fname) as tif:
16640
            assert len(tif.pages) == 1
16641
            page = tif.pages.first
16642
            assert page.shape == (4, 7, 31, 33)
16643
            assert page.axes == 'SZYX'
16644
            assert page.planarconfig == PLANARCONFIG.SEPARATE
16645
            assert page.photometric == PHOTOMETRIC.RGB
16646
            assert len(page.extrasamples) == 1
16647
            assert page.is_volumetric
16648

16649

16650
def test_write_auto_photometric_contig():
16651
    """Test detect photometric in contig mode."""
16652
    data = random_data(numpy.uint8, (31, 33, 4))
16653
    with TempFileName('write_auto_photometric_contig1') as fname:
16654
        imwrite(fname, data)
16655
        assert_valid_tiff(fname)
16656
        with TiffFile(fname) as tif:
16657
            assert len(tif.pages) == 1
16658
            page = tif.pages.first
16659
            assert page.shape == (31, 33, 4)
16660
            assert page.axes == 'YXS'
16661
            assert page.planarconfig == PLANARCONFIG.CONTIG
16662
            assert page.photometric == PHOTOMETRIC.RGB
16663
            assert len(page.extrasamples) == 1
16664

16665
    with TempFileName('write_auto_photometric_contig2') as fname:
16666
        imwrite(fname, data, planarconfig='contig')
16667
        assert_valid_tiff(fname)
16668
        with TiffFile(fname) as tif:
16669
            assert len(tif.pages) == 1
16670
            page = tif.pages.first
16671
            assert page.shape == (31, 33, 4)
16672
            assert page.axes == 'YXS'
16673
            assert page.planarconfig == PLANARCONFIG.CONTIG
16674
            assert page.photometric == PHOTOMETRIC.RGB
16675
            assert len(page.extrasamples) == 1
16676

16677
    data = random_data(numpy.uint8, (7, 31, 33, 4))
16678
    with TempFileName('write_auto_photometric_volumetric_contig1') as fname:
16679
        imwrite(fname, data, volumetric=True)
16680
        assert_valid_tiff(fname)
16681
        with TiffFile(fname) as tif:
16682
            assert len(tif.pages) == 1
16683
            page = tif.pages.first
16684
            assert page.shape == (7, 31, 33, 4)
16685
            assert page.axes == 'ZYXS'
16686
            assert page.planarconfig == PLANARCONFIG.CONTIG
16687
            assert page.photometric == PHOTOMETRIC.RGB
16688
            assert len(page.extrasamples) == 1
16689
            assert page.is_volumetric
16690

16691
    with TempFileName('write_auto_photometric_volumetric_contig2') as fname:
16692
        imwrite(fname, data, planarconfig='contig', volumetric=True)
16693
        assert_valid_tiff(fname)
16694
        with TiffFile(fname) as tif:
16695
            assert len(tif.pages) == 1
16696
            page = tif.pages.first
16697
            assert page.shape == (7, 31, 33, 4)
16698
            assert page.axes == 'ZYXS'
16699
            assert page.planarconfig == PLANARCONFIG.CONTIG
16700
            assert page.photometric == PHOTOMETRIC.RGB
16701
            assert len(page.extrasamples) == 1
16702
            assert page.is_volumetric
16703

16704

16705
def test_write_invalid_contig_rgb():
16706
    """Test write planar RGB with 2 samplesperpixel."""
16707
    data = random_data(numpy.uint8, (219, 301, 2))
16708
    with pytest.raises(ValueError):
16709
        with TempFileName('write_invalid_contig_rgb') as fname:
16710
            imwrite(fname, data, photometric=PHOTOMETRIC.RGB)
16711
    # default to pages
16712
    with TempFileName('write_invalid_contig_rgb_pages') as fname:
16713
        imwrite(fname, data)
16714
        assert_valid_tiff(fname)
16715
        with TiffFile(fname) as tif:
16716
            assert len(tif.pages) == 219
16717
            assert tif.series[0].axes == 'QYX'
16718
            page = tif.pages.first
16719
            assert page.is_contiguous
16720
            assert page.planarconfig == PLANARCONFIG.CONTIG
16721
            assert page.photometric != PHOTOMETRIC.RGB
16722
            assert page.imagewidth == 2
16723
            assert page.imagelength == 301
16724
            assert page.samplesperpixel == 1
16725
            image = tif.asarray()
16726
            assert_array_equal(data, image)
16727
            assert_aszarr_method(tif, image)
16728
            assert__str__(tif)
16729
    # better save as contig samples
16730
    with TempFileName('write_invalid_contig_rgb_samples') as fname:
16731
        imwrite(fname, data, planarconfig=PLANARCONFIG.CONTIG)
16732
        assert_valid_tiff(fname)
16733
        with TiffFile(fname) as tif:
16734
            assert len(tif.pages) == 1
16735
            assert tif.series[0].axes == 'YXS'
16736
            page = tif.pages.first
16737
            assert page.is_contiguous
16738
            assert page.planarconfig == PLANARCONFIG.CONTIG
16739
            assert page.photometric != PHOTOMETRIC.RGB
16740
            assert page.imagewidth == 301
16741
            assert page.imagelength == 219
16742
            assert page.samplesperpixel == 2
16743
            image = tif.asarray()
16744
            assert_array_equal(data, image)
16745
            assert_aszarr_method(tif, image)
16746
            assert__str__(tif)
16747

16748

16749
def test_write_invalid_planar_rgb():
16750
    """Test write planar RGB with 2 samplesperpixel."""
16751
    data = random_data(numpy.uint8, (2, 219, 301))
16752
    with pytest.raises(ValueError):
16753
        with TempFileName('write_invalid_planar_rgb') as fname:
16754
            imwrite(
16755
                fname,
16756
                data,
16757
                photometric=PHOTOMETRIC.RGB,
16758
                planarconfig=PLANARCONFIG.SEPARATE,
16759
            )
16760
    # default to pages
16761
    with TempFileName('write_invalid_planar_rgb_pages') as fname:
16762
        imwrite(fname, data)
16763
        assert_valid_tiff(fname)
16764
        with TiffFile(fname) as tif:
16765
            assert len(tif.pages) == 2
16766
            assert tif.series[0].axes == 'QYX'
16767
            page = tif.pages.first
16768
            assert page.is_contiguous
16769
            assert page.planarconfig == PLANARCONFIG.CONTIG
16770
            assert page.photometric != PHOTOMETRIC.RGB
16771
            assert page.imagewidth == 301
16772
            assert page.imagelength == 219
16773
            assert page.samplesperpixel == 1
16774
            image = tif.asarray()
16775
            assert_array_equal(data, image)
16776
            assert_aszarr_method(tif, image)
16777
            assert__str__(tif)
16778
    # or save as planar samples
16779
    with TempFileName('write_invalid_planar_rgb_samples') as fname:
16780
        imwrite(fname, data, planarconfig=PLANARCONFIG.SEPARATE)
16781
        assert_valid_tiff(fname)
16782
        with TiffFile(fname) as tif:
16783
            assert len(tif.pages) == 1
16784
            assert tif.series[0].axes == 'SYX'
16785
            page = tif.pages.first
16786
            assert page.is_contiguous
16787
            assert page.planarconfig == PLANARCONFIG.SEPARATE
16788
            assert page.photometric != PHOTOMETRIC.RGB
16789
            assert page.imagewidth == 301
16790
            assert page.imagelength == 219
16791
            assert page.samplesperpixel == 2
16792
            image = tif.asarray()
16793
            assert_array_equal(data, image)
16794
            assert_aszarr_method(tif, image)
16795
            assert__str__(tif)
16796

16797

16798
def test_write_extrasamples_gray():
16799
    """Test write grayscale with extrasamples contig."""
16800
    data = random_data(numpy.uint8, (301, 219, 2))
16801
    with TempFileName('write_extrasamples_gray') as fname:
16802
        imwrite(fname, data, extrasamples=[EXTRASAMPLE.UNASSALPHA])
16803
        assert_valid_tiff(fname)
16804
        with TiffFile(fname) as tif:
16805
            assert len(tif.pages) == 1
16806
            page = tif.pages.first
16807
            assert page.is_contiguous
16808
            assert page.photometric == PHOTOMETRIC.MINISBLACK
16809
            assert page.planarconfig == PLANARCONFIG.CONTIG
16810
            assert page.imagewidth == 219
16811
            assert page.imagelength == 301
16812
            assert page.samplesperpixel == 2
16813
            assert page.extrasamples[0] == 2
16814
            image = tif.asarray()
16815
            assert_array_equal(data, image)
16816
            assert_aszarr_method(tif, image)
16817
            assert__str__(tif)
16818

16819

16820
def test_write_extrasamples_gray_planar():
16821
    """Test write planar grayscale with extrasamples."""
16822
    data = random_data(numpy.uint8, (2, 301, 219))
16823
    with TempFileName('write_extrasamples_gray_planar') as fname:
16824
        imwrite(
16825
            fname,
16826
            data,
16827
            planarconfig=PLANARCONFIG.SEPARATE,
16828
            extrasamples=[EXTRASAMPLE.UNASSALPHA],
16829
        )
16830
        assert_valid_tiff(fname)
16831
        with TiffFile(fname) as tif:
16832
            assert len(tif.pages) == 1
16833
            page = tif.pages.first
16834
            assert page.is_contiguous
16835
            assert page.photometric == PHOTOMETRIC.MINISBLACK
16836
            assert page.planarconfig == PLANARCONFIG.SEPARATE
16837
            assert page.imagewidth == 219
16838
            assert page.imagelength == 301
16839
            assert page.samplesperpixel == 2
16840
            assert page.extrasamples[0] == 2
16841
            image = tif.asarray()
16842
            assert_array_equal(data, image)
16843
            assert_aszarr_method(tif, image)
16844
            assert__str__(tif)
16845

16846

16847
def test_write_extrasamples_gray_mix():
16848
    """Test write grayscale with multiple extrasamples."""
16849
    data = random_data(numpy.uint8, (301, 219, 4))
16850
    with TempFileName('write_extrasamples_gray_mix') as fname:
16851
        imwrite(
16852
            fname,
16853
            data,
16854
            photometric=PHOTOMETRIC.MINISBLACK,
16855
            extrasamples=[
16856
                EXTRASAMPLE.ASSOCALPHA,
16857
                EXTRASAMPLE.UNASSALPHA,
16858
                EXTRASAMPLE.UNSPECIFIED,
16859
            ],
16860
        )
16861
        assert_valid_tiff(fname)
16862
        with TiffFile(fname) as tif:
16863
            assert len(tif.pages) == 1
16864
            page = tif.pages.first
16865
            assert page.is_contiguous
16866
            assert page.photometric == PHOTOMETRIC.MINISBLACK
16867
            assert page.imagewidth == 219
16868
            assert page.imagelength == 301
16869
            assert page.samplesperpixel == 4
16870
            assert page.extrasamples == (1, 2, 0)
16871
            image = tif.asarray()
16872
            assert_array_equal(data, image)
16873
            assert_aszarr_method(tif, image)
16874
            assert__str__(tif)
16875

16876

16877
def test_write_extrasamples_unspecified():
16878
    """Test write RGB with unspecified extrasamples by default."""
16879
    data = random_data(numpy.uint8, (301, 219, 5))
16880
    with TempFileName('write_extrasamples_unspecified') as fname:
16881
        imwrite(fname, data, photometric=PHOTOMETRIC.RGB)
16882
        assert_valid_tiff(fname)
16883
        with TiffFile(fname) as tif:
16884
            assert len(tif.pages) == 1
16885
            page = tif.pages.first
16886
            assert page.is_contiguous
16887
            assert page.photometric == PHOTOMETRIC.RGB
16888
            assert page.imagewidth == 219
16889
            assert page.imagelength == 301
16890
            assert page.samplesperpixel == 5
16891
            assert page.extrasamples == (0, 0)
16892
            image = tif.asarray()
16893
            assert_array_equal(data, image)
16894
            assert_aszarr_method(tif, image)
16895
            assert__str__(tif)
16896

16897

16898
def test_write_extrasamples_assocalpha():
16899
    """Test write RGB with assocalpha extrasample."""
16900
    data = random_data(numpy.uint8, (219, 301, 4))
16901
    with TempFileName('write_extrasamples_assocalpha') as fname:
16902
        imwrite(
16903
            fname,
16904
            data,
16905
            photometric=PHOTOMETRIC.RGB,
16906
            extrasamples=EXTRASAMPLE.ASSOCALPHA,
16907
        )
16908
        assert_valid_tiff(fname)
16909
        with TiffFile(fname) as tif:
16910
            assert len(tif.pages) == 1
16911
            page = tif.pages.first
16912
            assert page.is_contiguous
16913
            assert page.planarconfig == PLANARCONFIG.CONTIG
16914
            assert page.photometric == PHOTOMETRIC.RGB
16915
            assert page.imagewidth == 301
16916
            assert page.imagelength == 219
16917
            assert page.samplesperpixel == 4
16918
            assert page.extrasamples[0] == 1
16919
            image = tif.asarray()
16920
            assert_array_equal(data, image)
16921
            assert_aszarr_method(tif, image)
16922
            assert__str__(tif)
16923

16924

16925
def test_write_extrasamples_mix():
16926
    """Test write RGB with mixture of extrasamples."""
16927
    data = random_data(numpy.uint8, (219, 301, 6))
16928
    with TempFileName('write_extrasamples_mix') as fname:
16929
        imwrite(
16930
            fname,
16931
            data,
16932
            photometric=PHOTOMETRIC.RGB,
16933
            extrasamples=[
16934
                EXTRASAMPLE.ASSOCALPHA,
16935
                EXTRASAMPLE.UNASSALPHA,
16936
                EXTRASAMPLE.UNSPECIFIED,
16937
            ],
16938
        )
16939
        assert_valid_tiff(fname)
16940
        with TiffFile(fname) as tif:
16941
            assert len(tif.pages) == 1
16942
            page = tif.pages.first
16943
            assert page.is_contiguous
16944
            assert page.planarconfig == PLANARCONFIG.CONTIG
16945
            assert page.photometric == PHOTOMETRIC.RGB
16946
            assert page.imagewidth == 301
16947
            assert page.imagelength == 219
16948
            assert page.samplesperpixel == 6
16949
            assert page.extrasamples == (1, 2, 0)
16950
            image = tif.asarray()
16951
            assert_array_equal(data, image)
16952
            assert_aszarr_method(tif, image)
16953
            assert__str__(tif)
16954

16955

16956
def test_write_extrasamples_contig():
16957
    """Test write contig grayscale with large number of extrasamples."""
16958
    data = random_data(numpy.uint8, (3, 219, 301))
16959
    with TempFileName('write_extrasamples_contig') as fname:
16960
        imwrite(fname, data, planarconfig=PLANARCONFIG.CONTIG)
16961
        assert_valid_tiff(fname)
16962
        with TiffFile(fname) as tif:
16963
            assert len(tif.pages) == 1
16964
            page = tif.pages.first
16965
            assert page.is_contiguous
16966
            assert page.planarconfig == PLANARCONFIG.CONTIG
16967
            assert page.photometric != PHOTOMETRIC.RGB
16968
            assert page.imagewidth == 219
16969
            assert page.imagelength == 3
16970
            assert page.samplesperpixel == 301
16971
            assert len(page.extrasamples) == 301 - 1
16972
            image = tif.asarray()
16973
            assert_array_equal(data, image)
16974
            assert_aszarr_method(tif, image)
16975
            assert__str__(tif)
16976
    # better save as RGB planar
16977
    with TempFileName('write_extrasamples_contig_planar') as fname:
16978
        imwrite(
16979
            fname,
16980
            data,
16981
            photometric=PHOTOMETRIC.RGB,
16982
            planarconfig=PLANARCONFIG.SEPARATE,
16983
        )
16984
        assert_valid_tiff(fname)
16985
        with TiffFile(fname) as tif:
16986
            assert len(tif.pages) == 1
16987
            page = tif.pages.first
16988
            assert page.is_contiguous
16989
            assert page.planarconfig == PLANARCONFIG.SEPARATE
16990
            assert page.photometric == PHOTOMETRIC.RGB
16991
            assert page.imagewidth == 301
16992
            assert page.imagelength == 219
16993
            assert page.samplesperpixel == 3
16994
            image = tif.asarray()
16995
            assert_array_equal(data, image)
16996
            assert_aszarr_method(tif, image)
16997
            assert__str__(tif)
16998

16999

17000
def test_write_extrasamples_contig_rgb2():
17001
    """Test write contig RGB with large number of extrasamples."""
17002
    data = random_data(numpy.uint8, (3, 219, 301))
17003
    with TempFileName('write_extrasamples_contig_rgb2') as fname:
17004
        imwrite(
17005
            fname,
17006
            data,
17007
            photometric=PHOTOMETRIC.RGB,
17008
            planarconfig=PLANARCONFIG.CONTIG,
17009
        )
17010
        assert_valid_tiff(fname)
17011
        with TiffFile(fname) as tif:
17012
            assert len(tif.pages) == 1
17013
            page = tif.pages.first
17014
            assert page.is_contiguous
17015
            assert page.planarconfig == PLANARCONFIG.CONTIG
17016
            assert page.photometric == PHOTOMETRIC.RGB
17017
            assert page.imagewidth == 219
17018
            assert page.imagelength == 3
17019
            assert page.samplesperpixel == 301
17020
            assert len(page.extrasamples) == 301 - 3
17021
            image = tif.asarray()
17022
            assert_array_equal(data, image)
17023
            assert_aszarr_method(tif, image)
17024
            assert__str__(tif)
17025
    # better save as planar
17026
    with TempFileName('write_extrasamples_contig_rgb2_planar') as fname:
17027
        imwrite(
17028
            fname,
17029
            data,
17030
            photometric=PHOTOMETRIC.RGB,
17031
            planarconfig=PLANARCONFIG.SEPARATE,
17032
        )
17033
        assert_valid_tiff(fname)
17034
        with TiffFile(fname) as tif:
17035
            assert len(tif.pages) == 1
17036
            page = tif.pages.first
17037
            assert page.is_contiguous
17038
            assert page.planarconfig == PLANARCONFIG.SEPARATE
17039
            assert page.photometric == PHOTOMETRIC.RGB
17040
            assert page.imagewidth == 301
17041
            assert page.imagelength == 219
17042
            assert page.samplesperpixel == 3
17043
            image = tif.asarray()
17044
            assert_array_equal(data, image)
17045
            assert_aszarr_method(tif, image)
17046
            assert__str__(tif)
17047

17048

17049
def test_write_extrasamples_planar():
17050
    """Test write planar large number of extrasamples."""
17051
    data = random_data(numpy.uint8, (219, 301, 3))
17052
    with TempFileName('write_extrasamples_planar') as fname:
17053
        imwrite(fname, data, planarconfig=PLANARCONFIG.SEPARATE)
17054
        assert_valid_tiff(fname)
17055
        with TiffFile(fname) as tif:
17056
            assert len(tif.pages) == 1
17057
            page = tif.pages.first
17058
            assert page.is_contiguous
17059
            assert page.planarconfig == PLANARCONFIG.SEPARATE
17060
            assert page.photometric != PHOTOMETRIC.RGB
17061
            assert page.imagewidth == 3
17062
            assert page.imagelength == 301
17063
            assert page.samplesperpixel == 219
17064
            assert len(page.extrasamples) == 219 - 1
17065
            image = tif.asarray()
17066
            assert_array_equal(data, image)
17067
            assert_aszarr_method(tif, image)
17068
            assert__str__(tif)
17069

17070

17071
def test_write_extrasamples_planar_rgb2():
17072
    """Test write planar RGB with large number of extrasamples."""
17073
    data = random_data(numpy.uint8, (219, 301, 3))
17074
    with TempFileName('write_extrasamples_planar_rgb2') as fname:
17075
        imwrite(
17076
            fname,
17077
            data,
17078
            photometric=PHOTOMETRIC.RGB,
17079
            planarconfig=PLANARCONFIG.SEPARATE,
17080
        )
17081
        assert_valid_tiff(fname)
17082
        with TiffFile(fname) as tif:
17083
            assert len(tif.pages) == 1
17084
            page = tif.pages.first
17085
            assert page.is_contiguous
17086
            assert page.planarconfig == PLANARCONFIG.SEPARATE
17087
            assert page.photometric == PHOTOMETRIC.RGB
17088
            assert page.imagewidth == 3
17089
            assert page.imagelength == 301
17090
            assert page.samplesperpixel == 219
17091
            assert len(page.extrasamples) == 219 - 3
17092
            image = tif.asarray()
17093
            assert_array_equal(data, image)
17094
            assert_aszarr_method(tif, image)
17095
            assert__str__(tif)
17096

17097

17098
def test_write_minisblack_planar():
17099
    """Test write planar minisblack."""
17100
    data = random_data(numpy.uint8, (3, 219, 301))
17101
    with TempFileName('write_minisblack_planar') as fname:
17102
        imwrite(fname, data, photometric=PHOTOMETRIC.MINISBLACK)
17103
        assert_valid_tiff(fname)
17104
        with TiffFile(fname) as tif:
17105
            assert len(tif.pages) == 3
17106
            page = tif.pages.first
17107
            assert page.is_contiguous
17108
            assert page.planarconfig == PLANARCONFIG.CONTIG
17109
            assert page.photometric != PHOTOMETRIC.RGB
17110
            assert page.imagewidth == 301
17111
            assert page.imagelength == 219
17112
            assert page.samplesperpixel == 1
17113
            image = tif.asarray()
17114
            assert_array_equal(data, image)
17115
            assert_aszarr_method(tif, image)
17116
            assert__str__(tif)
17117

17118

17119
def test_write_minisblack_contig():
17120
    """Test write contig minisblack."""
17121
    data = random_data(numpy.uint8, (219, 301, 3))
17122
    with TempFileName('write_minisblack_contig') as fname:
17123
        imwrite(fname, data, photometric=PHOTOMETRIC.MINISBLACK)
17124
        assert_valid_tiff(fname)
17125
        with TiffFile(fname) as tif:
17126
            assert len(tif.pages) == 219
17127
            page = tif.pages.first
17128
            assert page.is_contiguous
17129
            assert page.planarconfig == PLANARCONFIG.CONTIG
17130
            assert page.photometric != PHOTOMETRIC.RGB
17131
            assert page.imagewidth == 3
17132
            assert page.imagelength == 301
17133
            assert page.samplesperpixel == 1
17134
            image = tif.asarray()
17135
            assert_array_equal(data, image)
17136
            assert_aszarr_method(tif, image)
17137
            assert__str__(tif)
17138

17139

17140
def test_write_scalar():
17141
    """Test write 2D grayscale."""
17142
    data = random_data(numpy.uint8, (219, 301))
17143
    with TempFileName('write_scalar') as fname:
17144
        imwrite(fname, data)
17145
        assert_valid_tiff(fname)
17146
        with TiffFile(fname) as tif:
17147
            assert len(tif.pages) == 1
17148
            page = tif.pages.first
17149
            assert page.is_contiguous
17150
            assert page.planarconfig == PLANARCONFIG.CONTIG
17151
            assert page.photometric != PHOTOMETRIC.RGB
17152
            assert page.imagewidth == 301
17153
            assert page.imagelength == 219
17154
            assert page.samplesperpixel == 1
17155
            image = tif.asarray()
17156
            assert_array_equal(data, image)
17157
            assert_aszarr_method(tif, image)
17158
            assert__str__(tif)
17159

17160

17161
def test_write_scalar_3d():
17162
    """Test write 3D grayscale."""
17163
    data = random_data(numpy.uint8, (63, 219, 301))
17164
    with TempFileName('write_scalar_3d') as fname:
17165
        imwrite(fname, data)
17166
        assert_valid_tiff(fname)
17167
        with TiffFile(fname) as tif:
17168
            assert len(tif.pages) == 63
17169
            page = tif.pages[62]
17170
            assert page.is_contiguous
17171
            assert page.planarconfig == PLANARCONFIG.CONTIG
17172
            assert page.photometric != PHOTOMETRIC.RGB
17173
            assert page.imagewidth == 301
17174
            assert page.imagelength == 219
17175
            assert page.samplesperpixel == 1
17176
            image = tif.asarray()
17177
            assert isinstance(image, numpy.ndarray)
17178
            assert_array_equal(data, image)
17179
            assert_aszarr_method(tif, image)
17180
            assert__str__(tif)
17181

17182

17183
def test_write_scalar_4d():
17184
    """Test write 4D grayscale."""
17185
    data = random_data(numpy.uint8, (3, 2, 219, 301))
17186
    with TempFileName('write_scalar_4d') as fname:
17187
        imwrite(fname, data)
17188
        assert_valid_tiff(fname)
17189
        with TiffFile(fname) as tif:
17190
            assert len(tif.pages) == 6
17191
            page = tif.pages[5]
17192
            assert page.is_contiguous
17193
            assert page.planarconfig == PLANARCONFIG.CONTIG
17194
            assert page.photometric != PHOTOMETRIC.RGB
17195
            assert page.imagewidth == 301
17196
            assert page.imagelength == 219
17197
            assert page.samplesperpixel == 1
17198
            image = tif.asarray()
17199
            assert_array_equal(data, image)
17200
            assert_aszarr_method(tif, image)
17201
            assert__str__(tif)
17202

17203

17204
def test_write_contig_extrasample():
17205
    """Test write grayscale with contig extrasamples."""
17206
    data = random_data(numpy.uint8, (219, 301, 2))
17207
    with TempFileName('write_contig_extrasample') as fname:
17208
        imwrite(fname, data, planarconfig=PLANARCONFIG.CONTIG)
17209
        assert_valid_tiff(fname)
17210
        with TiffFile(fname) as tif:
17211
            assert len(tif.pages) == 1
17212
            page = tif.pages.first
17213
            assert page.is_contiguous
17214
            assert page.planarconfig == PLANARCONFIG.CONTIG
17215
            assert page.photometric != PHOTOMETRIC.RGB
17216
            assert page.imagewidth == 301
17217
            assert page.imagelength == 219
17218
            assert page.samplesperpixel == 2
17219
            image = tif.asarray()
17220
            assert_array_equal(data, image)
17221
            assert_aszarr_method(tif, image)
17222
            assert__str__(tif)
17223

17224

17225
def test_write_planar_extrasample():
17226
    """Test write grayscale with planar extrasamples."""
17227
    data = random_data(numpy.uint8, (2, 219, 301))
17228
    with TempFileName('write_planar_extrasample') as fname:
17229
        imwrite(fname, data, planarconfig=PLANARCONFIG.SEPARATE)
17230
        assert_valid_tiff(fname)
17231
        with TiffFile(fname) as tif:
17232
            assert len(tif.pages) == 1
17233
            page = tif.pages.first
17234
            assert page.is_contiguous
17235
            assert page.planarconfig == PLANARCONFIG.SEPARATE
17236
            assert page.photometric != PHOTOMETRIC.RGB
17237
            assert page.imagewidth == 301
17238
            assert page.imagelength == 219
17239
            assert page.samplesperpixel == 2
17240
            image = tif.asarray()
17241
            assert_array_equal(data, image)
17242
            assert_aszarr_method(tif, image)
17243
            assert__str__(tif)
17244

17245

17246
def test_write_auto_rgb_contig():
17247
    """Test write auto contig RGB."""
17248
    data = random_data(numpy.uint8, (219, 301, 3))
17249
    with TempFileName('write_auto_rgb_contig') as fname:
17250
        imwrite(fname, data)  # photometric=RGB
17251
        assert_valid_tiff(fname)
17252
        with TiffFile(fname) as tif:
17253
            assert len(tif.pages) == 1
17254
            page = tif.pages.first
17255
            assert page.is_contiguous
17256
            assert page.planarconfig == PLANARCONFIG.CONTIG
17257
            assert page.photometric == PHOTOMETRIC.RGB
17258
            assert page.imagewidth == 301
17259
            assert page.imagelength == 219
17260
            assert page.samplesperpixel == 3
17261
            image = tif.asarray()
17262
            assert_array_equal(data, image)
17263
            assert_aszarr_method(tif, image)
17264
            assert__str__(tif)
17265

17266

17267
def test_write_auto_rgb_planar():
17268
    """Test write auto planar RGB."""
17269
    data = random_data(numpy.uint8, (3, 219, 301))
17270
    with TempFileName('write_auto_rgb_planar') as fname:
17271
        with pytest.warns(DeprecationWarning):
17272
            imwrite(fname, data)  # photometric=RGB, planarconfig=SEPARATE
17273
        assert_valid_tiff(fname)
17274
        with TiffFile(fname) as tif:
17275
            assert len(tif.pages) == 1
17276
            page = tif.pages.first
17277
            assert page.is_contiguous
17278
            assert page.planarconfig == PLANARCONFIG.SEPARATE
17279
            assert page.photometric == PHOTOMETRIC.RGB
17280
            assert page.imagewidth == 301
17281
            assert page.imagelength == 219
17282
            assert page.samplesperpixel == 3
17283
            image = tif.asarray()
17284
            assert_array_equal(data, image)
17285
            assert_aszarr_method(tif, image)
17286
            assert__str__(tif)
17287

17288

17289
def test_write_auto_rgba_contig():
17290
    """Test write auto contig RGBA."""
17291
    data = random_data(numpy.uint8, (219, 301, 4))
17292
    with TempFileName('write_auto_rgba_contig') as fname:
17293
        imwrite(fname, data)  # photometric=RGB
17294
        assert_valid_tiff(fname)
17295
        with TiffFile(fname) as tif:
17296
            assert len(tif.pages) == 1
17297
            page = tif.pages.first
17298
            assert page.is_contiguous
17299
            assert page.planarconfig == PLANARCONFIG.CONTIG
17300
            assert page.photometric == PHOTOMETRIC.RGB
17301
            assert page.imagewidth == 301
17302
            assert page.imagelength == 219
17303
            assert page.samplesperpixel == 4
17304
            assert page.extrasamples[0] == EXTRASAMPLE.UNASSALPHA
17305
            image = tif.asarray()
17306
            assert_array_equal(data, image)
17307
            assert_aszarr_method(tif, image)
17308
            assert__str__(tif)
17309

17310

17311
def test_write_auto_rgba_planar():
17312
    """Test write auto planar RGBA."""
17313
    data = random_data(numpy.uint8, (4, 219, 301))
17314
    with TempFileName('write_auto_rgba_planar') as fname:
17315
        with pytest.warns(DeprecationWarning):
17316
            imwrite(fname, data)  # photometric=RGB, planarconfig=SEPARATE
17317
        assert_valid_tiff(fname)
17318
        with TiffFile(fname) as tif:
17319
            assert len(tif.pages) == 1
17320
            page = tif.pages.first
17321
            assert page.is_contiguous
17322
            assert page.planarconfig == PLANARCONFIG.SEPARATE
17323
            assert page.photometric == PHOTOMETRIC.RGB
17324
            assert page.imagewidth == 301
17325
            assert page.imagelength == 219
17326
            assert page.samplesperpixel == 4
17327
            assert page.extrasamples[0] == EXTRASAMPLE.UNASSALPHA
17328
            image = tif.asarray()
17329
            assert_array_equal(data, image)
17330
            assert_aszarr_method(tif, image)
17331
            assert__str__(tif)
17332

17333

17334
def test_write_extrasamples_contig_rgb():
17335
    """Test write contig RGB with extrasamples."""
17336
    data = random_data(numpy.uint8, (219, 301, 8))
17337
    with TempFileName('write_extrasamples_contig') as fname:
17338
        imwrite(fname, data, photometric=PHOTOMETRIC.RGB)
17339
        assert_valid_tiff(fname)
17340
        with TiffFile(fname) as tif:
17341
            assert len(tif.pages) == 1
17342
            page = tif.pages.first
17343
            assert page.is_contiguous
17344
            assert page.planarconfig == PLANARCONFIG.CONTIG
17345
            assert page.photometric == PHOTOMETRIC.RGB
17346
            assert page.imagewidth == 301
17347
            assert page.imagelength == 219
17348
            assert page.samplesperpixel == 8
17349
            assert len(page.extrasamples) == 5
17350
            assert page.extrasamples[0] == EXTRASAMPLE.UNSPECIFIED
17351
            image = tif.asarray()
17352
            assert_array_equal(data, image)
17353
            assert_aszarr_method(tif, image)
17354
            assert__str__(tif)
17355

17356

17357
def test_write_extrasamples_planar_rgb():
17358
    """Test write planar RGB with extrasamples."""
17359
    data = random_data(numpy.uint8, (8, 219, 301))
17360
    with TempFileName('write_extrasamples_planar') as fname:
17361
        imwrite(fname, data, photometric=PHOTOMETRIC.RGB)
17362
        assert_valid_tiff(fname)
17363
        with TiffFile(fname) as tif:
17364
            assert len(tif.pages) == 1
17365
            page = tif.pages.first
17366
            assert page.is_contiguous
17367
            assert page.planarconfig == PLANARCONFIG.SEPARATE
17368
            assert page.photometric == PHOTOMETRIC.RGB
17369
            assert page.imagewidth == 301
17370
            assert page.imagelength == 219
17371
            assert page.samplesperpixel == 8
17372
            assert len(page.extrasamples) == 5
17373
            assert page.extrasamples[0] == EXTRASAMPLE.UNSPECIFIED
17374
            image = tif.asarray()
17375
            assert_array_equal(data, image)
17376
            assert_aszarr_method(tif, image)
17377
            assert__str__(tif)
17378

17379

17380
@pytest.mark.skipif(SKIP_CODECS, reason=REASON)
17381
def test_write_iccprofile():
17382
    """Test write RGB with ICC profile."""
17383
    data = random_data(numpy.uint8, (219, 301, 3))
17384
    iccprofile = imagecodecs.cms_profile('srgb')
17385

17386
    with TempFileName('write_iccprofile') as fname:
17387
        imwrite(
17388
            fname, data, photometric=PHOTOMETRIC.RGB, iccprofile=iccprofile
17389
        )
17390
        assert_valid_tiff(fname)
17391
        with TiffFile(fname) as tif:
17392
            assert len(tif.pages) == 1
17393
            page = tif.pages.first
17394
            assert page.is_contiguous
17395
            assert page.planarconfig == PLANARCONFIG.CONTIG
17396
            assert page.photometric == PHOTOMETRIC.RGB
17397
            assert page.imagewidth == 301
17398
            assert page.imagelength == 219
17399
            assert page.samplesperpixel == 3
17400
            assert page.tags[34675].dtype == DATATYPE.UNDEFINED
17401
            assert page.iccprofile == iccprofile
17402
            imagecodecs.cms_profile_validate(page.iccprofile)
17403
            tif.asarray()
17404
            assert__str__(tif)
17405

17406

17407
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
17408
def test_write_cfa():
17409
    """Test write uncompressed CFA image."""
17410
    # TODO: write a valid TIFF/EP file
17411
    data = imread(
17412
        private_file('DNG/cinemadng/M14-1451_000085_cDNG_uncompressed.dng')
17413
    )
17414
    extratags = [
17415
        (271, 's', 4, 'Make', False),
17416
        (272, 's', 5, 'Model', False),
17417
        (33421, 'H', 2, (2, 2), False),  # CFARepeatPatternDim
17418
        (33422, 'B', 4, b'\x00\x01\x01\x02', False),  # CFAPattern
17419
        # (37398, 'B', 4, b'\x01\x00\x00\x00', False),  # TIFF/EPStandardID
17420
        # (37399, 'H', 1, 0)  # SensingMethod Undefined
17421
        # (50706, 'B', 4, b'\x01\x04\x00\x00', False),  # DNGVersion
17422
    ]
17423
    with TempFileName('write_cfa') as fname:
17424
        imwrite(
17425
            fname,
17426
            data,
17427
            photometric=PHOTOMETRIC.CFA,
17428
            software='Tifffile',
17429
            datetime=True,
17430
            extratags=extratags,
17431
        )
17432
        with TiffFile(fname) as tif:
17433
            assert len(tif.pages) == 1
17434
            page = tif.pages.first
17435
            assert page.compression == 1
17436
            assert page.photometric == PHOTOMETRIC.CFA
17437
            assert page.imagewidth == 960
17438
            assert page.imagelength == 540
17439
            assert page.bitspersample == 16
17440
            assert page.tags['CFARepeatPatternDim'].value == (2, 2)
17441
            assert page.tags['CFAPattern'].value == b'\x00\x01\x01\x02'
17442
            assert_array_equal(page.asarray(), data)
17443
            assert_aszarr_method(page, data)
17444

17445

17446
def test_write_tiled_compressed():
17447
    """Test write compressed tiles."""
17448
    data = random_data(numpy.uint8, (3, 219, 301))
17449
    with TempFileName('write_tiled_compressed') as fname:
17450
        imwrite(
17451
            fname,
17452
            data,
17453
            photometric=PHOTOMETRIC.RGB,
17454
            planarconfig=PLANARCONFIG.SEPARATE,
17455
            compression=COMPRESSION.ADOBE_DEFLATE,
17456
            compressionargs={'level': -1},
17457
            tile=(96, 64),
17458
        )
17459
        assert_valid_tiff(fname)
17460
        with TiffFile(fname) as tif:
17461
            assert len(tif.pages) == 1
17462
            page = tif.pages.first
17463
            assert page.is_tiled
17464
            assert not page.is_contiguous
17465
            assert page.planarconfig == PLANARCONFIG.SEPARATE
17466
            assert page.photometric == PHOTOMETRIC.RGB
17467
            assert page.imagewidth == 301
17468
            assert page.imagelength == 219
17469
            assert page.tilewidth == 64
17470
            assert page.tilelength == 96
17471
            assert page.samplesperpixel == 3
17472
            image = tif.asarray()
17473
            assert_array_equal(data, image)
17474
            assert_aszarr_method(tif, image)
17475
            assert__str__(tif)
17476

17477

17478
def test_write_tiled():
17479
    """Test write tiled."""
17480
    data = random_data(numpy.uint16, (219, 301))
17481
    with TempFileName('write_tiled') as fname:
17482
        imwrite(fname, data, tile=(96, 64))
17483
        assert_valid_tiff(fname)
17484
        with TiffFile(fname) as tif:
17485
            assert len(tif.pages) == 1
17486
            page = tif.pages.first
17487
            assert page.is_tiled
17488
            assert not page.is_contiguous
17489
            assert page.planarconfig == PLANARCONFIG.CONTIG
17490
            assert page.photometric != PHOTOMETRIC.RGB
17491
            assert page.imagewidth == 301
17492
            assert page.imagelength == 219
17493
            assert page.tilewidth == 64
17494
            assert page.tilelength == 96
17495
            assert page.samplesperpixel == 1
17496
            image = tif.asarray()
17497
            assert_array_equal(data, image)
17498
            assert_aszarr_method(tif, image)
17499
            assert__str__(tif)
17500

17501

17502
def test_write_tiled_planar():
17503
    """Test write planar tiles."""
17504
    data = random_data(numpy.uint8, (4, 219, 301))
17505
    with TempFileName('write_tiled_planar') as fname:
17506
        imwrite(
17507
            fname,
17508
            data,
17509
            tile=(96, 64),
17510
            photometric=PHOTOMETRIC.RGB,
17511
            planarconfig=PLANARCONFIG.SEPARATE,
17512
        )
17513
        assert_valid_tiff(fname)
17514
        with TiffFile(fname) as tif:
17515
            assert len(tif.pages) == 1
17516
            page = tif.pages.first
17517
            assert page.is_tiled
17518
            assert not page.is_contiguous
17519
            assert not page.is_volumetric
17520
            assert page.planarconfig == PLANARCONFIG.SEPARATE
17521
            assert page.photometric == PHOTOMETRIC.RGB
17522
            assert page.imagewidth == 301
17523
            assert page.imagelength == 219
17524
            assert page.tilewidth == 64
17525
            assert page.tilelength == 96
17526
            assert page.samplesperpixel == 4
17527
            image = tif.asarray()
17528
            assert_array_equal(data, image)
17529
            assert_aszarr_method(tif, image)
17530
            assert__str__(tif)
17531

17532

17533
def test_write_tiled_contig():
17534
    """Test write contig tiles."""
17535
    data = random_data(numpy.uint8, (219, 301, 3))
17536
    with TempFileName('write_tiled_contig') as fname:
17537
        imwrite(fname, data, tile=(96, 64), photometric=PHOTOMETRIC.RGB)
17538
        assert_valid_tiff(fname)
17539
        with TiffFile(fname) as tif:
17540
            assert len(tif.pages) == 1
17541
            page = tif.pages.first
17542
            assert page.is_tiled
17543
            assert not page.is_contiguous
17544
            assert page.planarconfig == PLANARCONFIG.CONTIG
17545
            assert page.photometric == PHOTOMETRIC.RGB
17546
            assert page.imagewidth == 301
17547
            assert page.imagelength == 219
17548
            assert page.tilewidth == 64
17549
            assert page.tilelength == 96
17550
            assert page.samplesperpixel == 3
17551
            image = tif.asarray()
17552
            assert_array_equal(data, image)
17553
            assert_aszarr_method(tif, image)
17554
            assert__str__(tif)
17555

17556

17557
def test_write_tiled_pages():
17558
    """Test write multiple tiled pages."""
17559
    data = random_data(numpy.uint8, (5, 219, 301, 3))
17560
    with TempFileName('write_tiled_pages') as fname:
17561
        imwrite(fname, data, tile=(96, 64), photometric=PHOTOMETRIC.RGB)
17562
        assert_valid_tiff(fname)
17563
        with TiffFile(fname) as tif:
17564
            assert len(tif.pages) == 5
17565
            page = tif.pages.first
17566
            assert page.is_tiled
17567
            assert not page.is_contiguous
17568
            assert page.planarconfig == PLANARCONFIG.CONTIG
17569
            assert page.photometric == PHOTOMETRIC.RGB
17570
            assert not page.is_volumetric
17571
            assert page.imagewidth == 301
17572
            assert page.imagelength == 219
17573
            assert page.tilewidth == 64
17574
            assert page.tilelength == 96
17575
            assert page.samplesperpixel == 3
17576
            image = tif.asarray()
17577
            assert_array_equal(data, image)
17578
            assert_aszarr_method(tif, image)
17579
            assert__str__(tif)
17580

17581

17582
@pytest.mark.parametrize('compression', [1, 8])
17583
def test_write_iter_tiles(compression):
17584
    """Test write tiles from iterator."""
17585
    data = random_data(numpy.uint16, (12, 16, 16))
17586

17587
    def tiles():
17588
        for i in range(data.shape[0]):
17589
            yield data[i]
17590

17591
    with TempFileName(f'write_iter_tiles_{compression}') as fname:
17592
        with pytest.raises((StopIteration, RuntimeError)):
17593
            # missing tiles
17594
            imwrite(
17595
                fname,
17596
                tiles(),
17597
                shape=(43, 81),
17598
                tile=(16, 16),
17599
                dtype=numpy.uint16,
17600
                compression=compression,
17601
            )
17602

17603
        with pytest.raises(ValueError):
17604
            # missing parameters
17605
            imwrite(fname, tiles(), compression=compression)
17606

17607
        with pytest.raises(ValueError):
17608
            # missing parameters
17609
            imwrite(fname, tiles(), shape=(43, 81), compression=compression)
17610

17611
        with pytest.raises(ValueError):
17612
            # dtype mismatch
17613
            imwrite(
17614
                fname,
17615
                tiles(),
17616
                shape=(43, 61),
17617
                tile=(16, 16),
17618
                dtype=numpy.uint32,
17619
                compression=compression,
17620
            )
17621

17622
        with pytest.raises(ValueError):
17623
            # shape mismatch
17624
            imwrite(
17625
                fname,
17626
                tiles(),
17627
                shape=(43, 61),
17628
                tile=(8, 8),
17629
                dtype=numpy.uint16,
17630
                compression=compression,
17631
            )
17632

17633
        imwrite(
17634
            fname,
17635
            tiles(),
17636
            shape=(43, 61),
17637
            tile=(16, 16),
17638
            dtype=numpy.uint16,
17639
            compression=compression,
17640
        )
17641

17642
        with TiffFile(fname) as tif:
17643
            page = tif.pages.first
17644
            assert page.shape == (43, 61)
17645
            assert page.tilelength == 16
17646
            assert page.tilewidth == 16
17647
            assert page.compression == compression
17648
            image = page.asarray()
17649
            assert_array_equal(image[:16, :16], data[0])
17650
            for i, segment in enumerate(page.segments()):
17651
                assert_array_equal(numpy.squeeze(segment[0]), data[i])
17652

17653

17654
@pytest.mark.parametrize('compression', [1, 8])
17655
def test_write_iter_tiles_separate(compression):
17656
    """Test write separate tiles from iterator."""
17657
    data = random_data(numpy.uint16, (24, 16, 16))
17658

17659
    def tiles():
17660
        for i in range(data.shape[0]):
17661
            yield data[i]
17662

17663
    with TempFileName(f'write_iter_tiles_separate_{compression}') as fname:
17664
        imwrite(
17665
            fname,
17666
            tiles(),
17667
            shape=(2, 43, 61),
17668
            tile=(16, 16),
17669
            dtype=numpy.uint16,
17670
            planarconfig=PLANARCONFIG.SEPARATE,
17671
            compression=compression,
17672
        )
17673

17674
        with TiffFile(fname) as tif:
17675
            assert len(tif.pages) == 1
17676
            page = tif.pages.first
17677
            assert page.shape == (2, 43, 61)
17678
            assert page.tilelength == 16
17679
            assert page.tilewidth == 16
17680
            assert page.planarconfig == 2
17681
            image = page.asarray()
17682
            assert_array_equal(image[0, :16, :16], data[0])
17683
            for i, segment in enumerate(page.segments()):
17684
                assert_array_equal(numpy.squeeze(segment[0]), data[i])
17685

17686

17687
@pytest.mark.parametrize('compression', [1, 8])
17688
def test_write_iter_tiles_none(compression):
17689
    """Test write tiles from iterator with missing tiles.
17690

17691
    Missing tiles are not with tileoffset=0 and tilebytecount=0.
17692

17693
    """
17694
    data = random_data(numpy.uint16, (12, 16, 16))
17695

17696
    def tiles():
17697
        for i in range(data.shape[0]):
17698
            if i % 3 == 1:
17699
                data[i] = 0
17700
                yield None
17701
            else:
17702
                yield data[i]
17703

17704
    with TempFileName(f'write_iter_tiles_none_{compression}') as fname:
17705
        imwrite(
17706
            fname,
17707
            tiles(),
17708
            shape=(43, 61),
17709
            tile=(16, 16),
17710
            dtype=numpy.uint16,
17711
            compression=compression,
17712
        )
17713
        with TiffFile(fname) as tif:
17714
            page = tif.pages.first
17715
            assert page.shape == (43, 61)
17716
            assert page.tilelength == 16
17717
            assert page.tilewidth == 16
17718
            assert page.databytecounts[1] == 0
17719
            assert page.dataoffsets[1] == 0
17720
            image = page.asarray()
17721
            assert_array_equal(image[:16, :16], data[0])
17722
            for i, segment in enumerate(page.segments()):
17723
                if i % 3 == 1:
17724
                    assert segment[0] is None
17725
                else:
17726
                    assert_array_equal(numpy.squeeze(segment[0]), data[i])
17727

17728

17729
@pytest.mark.parametrize('compression', [1, 8])
17730
def test_write_iter_tiles_bytes(compression):
17731
    """Test write tiles from iterator of bytes."""
17732
    data = random_data(numpy.uint16, (5, 3, 15, 17))
17733

17734
    with TempFileName(f'write_iter_tiles_bytes_{compression}') as fname:
17735
        imwrite(
17736
            fname + 'f',
17737
            data,
17738
            tile=(16, 16),
17739
            compression=compression,
17740
            planarconfig='separate',
17741
            photometric='rgb',
17742
        )
17743

17744
        def tiles():
17745
            with TiffFile(fname + 'f') as tif:
17746
                fh = tif.filehandle
17747
                for page in tif.pages:
17748
                    for offset, bytecount in zip(
17749
                        page.dataoffsets, page.databytecounts
17750
                    ):
17751
                        fh.seek(offset)
17752
                        strip = fh.read(bytecount)
17753
                        yield strip
17754

17755
        imwrite(
17756
            fname,
17757
            tiles(),
17758
            shape=data.shape,
17759
            dtype=data.dtype,
17760
            tile=(16, 16),
17761
            compression=compression,
17762
            planarconfig='separate',
17763
            photometric='rgb',
17764
        )
17765
        assert_array_equal(imread(fname), data)
17766

17767

17768
@pytest.mark.parametrize('compression', [1, 8])
17769
@pytest.mark.parametrize('rowsperstrip', [5, 16])
17770
def test_write_iter_strips_bytes(compression, rowsperstrip):
17771
    """Test write strips from iterator of bytes."""
17772
    data = random_data(numpy.uint16, (5, 3, 16, 16))
17773

17774
    with TempFileName(
17775
        f'write_iter_strips_bytes_{compression}{rowsperstrip}'
17776
    ) as fname:
17777
        imwrite(
17778
            fname + 'f',
17779
            data,
17780
            rowsperstrip=rowsperstrip,
17781
            compression=compression,
17782
            planarconfig='separate',
17783
            photometric='rgb',
17784
        )
17785

17786
        def strips():
17787
            with TiffFile(fname + 'f') as tif:
17788
                fh = tif.filehandle
17789
                for page in tif.pages:
17790
                    for offset, bytecount in zip(
17791
                        page.dataoffsets, page.databytecounts
17792
                    ):
17793
                        fh.seek(offset)
17794
                        strip = fh.read(bytecount)
17795
                        yield strip
17796

17797
        imwrite(
17798
            fname,
17799
            strips(),
17800
            shape=data.shape,
17801
            dtype=data.dtype,
17802
            rowsperstrip=rowsperstrip,
17803
            compression=compression,
17804
            planarconfig='separate',
17805
            photometric='rgb',
17806
        )
17807
        assert_array_equal(imread(fname), data)
17808

17809

17810
@pytest.mark.parametrize('compression', [1, 8])
17811
@pytest.mark.parametrize('rowsperstrip', [5, 16])
17812
def test_write_iter_pages_none(compression, rowsperstrip):
17813
    """Test write pages from iterator with missing pages.
17814

17815
    Missing pages are written as zeros.
17816

17817
    """
17818
    data = random_data(numpy.uint16, (12, 16, 16))
17819

17820
    def pages():
17821
        for i in range(data.shape[0]):
17822
            if i % 3 == 1:
17823
                data[i] = 0
17824
                yield None
17825
            else:
17826
                yield data[i]
17827

17828
    with TempFileName(
17829
        f'write_iter_pages_none_{compression}{rowsperstrip}'
17830
    ) as fname:
17831
        imwrite(
17832
            fname,
17833
            pages(),
17834
            shape=(12, 16, 16),
17835
            dtype=numpy.uint16,
17836
            rowsperstrip=rowsperstrip,
17837
            compression=compression,
17838
        )
17839
        with TiffFile(fname) as tif:
17840
            for i, page in enumerate(tif.pages):
17841
                assert page.shape == (16, 16)
17842
                assert page.rowsperstrip == rowsperstrip
17843
                assert_array_equal(page.asarray(), data[i])
17844
                for j, segment in enumerate(page.segments()):
17845
                    assert_array_equal(
17846
                        numpy.squeeze(segment[0]),
17847
                        numpy.squeeze(
17848
                            data[i, j * rowsperstrip : (j + 1) * rowsperstrip]
17849
                        ),
17850
                    )
17851

17852

17853
def test_write_pyramids():
17854
    """Test write two pyramids to shaped file."""
17855
    data = random_data(numpy.uint8, (31, 64, 96, 3))
17856
    with TempFileName('write_pyramids') as fname:
17857
        with TiffWriter(fname) as tif:
17858
            # use pages
17859
            tif.write(data, tile=(16, 16), photometric=PHOTOMETRIC.RGB)
17860
            # interrupt pyramid, for example thumbnail
17861
            tif.write(data[0, :, :, 0])
17862
            # pyramid levels
17863
            tif.write(
17864
                data[:, ::2, ::2],
17865
                tile=(16, 16),
17866
                subfiletype=FILETYPE.REDUCEDIMAGE,
17867
                photometric=PHOTOMETRIC.RGB,
17868
            )
17869
            tif.write(
17870
                data[:, ::4, ::4],
17871
                tile=(16, 16),
17872
                subfiletype=FILETYPE.REDUCEDIMAGE,
17873
                photometric=PHOTOMETRIC.RGB,
17874
            )
17875
            # second pyramid using volumetric with downsampling factor 3
17876
            tif.write(data, tile=(16, 16, 16), photometric=PHOTOMETRIC.RGB)
17877
            tif.write(
17878
                data[::3, ::3, ::3],
17879
                tile=(16, 16, 16),
17880
                subfiletype=FILETYPE.REDUCEDIMAGE,
17881
                photometric=PHOTOMETRIC.RGB,
17882
            )
17883

17884
        assert_valid_tiff(fname)
17885

17886
        with TiffFile(fname) as tif:
17887
            assert len(tif.pages) == 3 * 31 + 2 + 1
17888
            assert len(tif.series) == 3
17889

17890
            series = tif.series[0]
17891
            assert series.kind == 'shaped'
17892
            assert series.is_pyramidal
17893
            assert len(series.levels) == 3
17894
            assert len(series.levels[0].pages) == 31
17895
            assert len(series.levels[1].pages) == 31
17896
            assert len(series.levels[2].pages) == 31
17897
            assert series.levels[0].shape == (31, 64, 96, 3)
17898
            assert series.levels[1].shape == (31, 32, 48, 3)
17899
            assert series.levels[2].shape == (31, 16, 24, 3)
17900

17901
            series = tif.series[1]
17902
            assert series.kind == 'shaped'
17903
            assert not series.is_pyramidal
17904
            assert series.shape == (64, 96)
17905

17906
            series = tif.series[2]
17907
            assert series.kind == 'shaped'
17908
            assert series.is_pyramidal
17909
            assert len(series.levels) == 2
17910
            assert len(series.levels[0].pages) == 1
17911
            assert len(series.levels[1].pages) == 1
17912
            assert series.levels[0].keyframe.is_volumetric
17913
            assert series.levels[1].keyframe.is_volumetric
17914
            assert series.levels[0].shape == (31, 64, 96, 3)
17915
            assert series.levels[1].shape == (11, 22, 32, 3)
17916

17917
            assert_array_equal(tif.asarray(), data)
17918
            assert_array_equal(tif.asarray(series=0, level=0), data)
17919
            assert_aszarr_method(tif, data, series=0, level=0)
17920

17921
            assert_array_equal(
17922
                data[:, ::2, ::2], tif.asarray(series=0, level=1)
17923
            )
17924
            assert_aszarr_method(tif, data[:, ::2, ::2], series=0, level=1)
17925

17926
            assert_array_equal(
17927
                data[:, ::4, ::4], tif.asarray(series=0, level=2)
17928
            )
17929
            assert_aszarr_method(tif, data[:, ::4, ::4], series=0, level=2)
17930

17931
            assert_array_equal(data[0, :, :, 0], tif.asarray(series=1))
17932
            assert_aszarr_method(tif, data[0, :, :, 0], series=1)
17933

17934
            assert_array_equal(data, tif.asarray(series=2, level=0))
17935
            assert_aszarr_method(tif, data, series=2, level=0)
17936

17937
            assert_array_equal(
17938
                data[::3, ::3, ::3], tif.asarray(series=2, level=1)
17939
            )
17940
            assert_aszarr_method(tif, data[::3, ::3, ::3], series=2, level=1)
17941

17942
            assert__str__(tif)
17943

17944

17945
def test_write_volumetric_tiled():
17946
    """Test write tiled volume."""
17947
    data = random_data(numpy.uint8, (253, 64, 96))
17948
    with TempFileName('write_volumetric_tiled') as fname:
17949
        imwrite(fname, data, tile=(64, 64, 64))
17950
        assert_valid_tiff(fname)
17951
        with TiffFile(fname) as tif:
17952
            assert len(tif.pages) == 1
17953
            page = tif.pages.first
17954
            assert page.is_volumetric
17955
            assert page.is_tiled
17956
            assert not page.is_contiguous
17957
            assert page.planarconfig == PLANARCONFIG.CONTIG
17958
            assert page.photometric != PHOTOMETRIC.RGB
17959
            assert page.imagewidth == 96
17960
            assert page.imagelength == 64
17961
            assert page.imagedepth == 253
17962
            assert page.tilewidth == 64
17963
            assert page.tilelength == 64
17964
            assert page.tiledepth == 64
17965
            assert page.tile == (64, 64, 64)
17966
            assert page.samplesperpixel == 1
17967
            image = tif.asarray()
17968
            assert_array_equal(data, image)
17969
            assert_aszarr_method(tif, image)
17970
            assert__str__(tif)
17971

17972

17973
@pytest.mark.skipif(SKIP_CODECS, reason=REASON)
17974
def test_write_volumetric_tiled_png():
17975
    """Test write tiled volume using an image compressor."""
17976
    data = random_data(numpy.uint8, (16, 64, 96, 3))
17977
    with TempFileName('write_volumetric_tiled_png') as fname:
17978
        imwrite(
17979
            fname,
17980
            data,
17981
            tile=(1, 64, 64),
17982
            photometric=PHOTOMETRIC.RGB,
17983
            compression=COMPRESSION.PNG,
17984
        )
17985
        assert_valid_tiff(fname)
17986
        with TiffFile(fname) as tif:
17987
            assert len(tif.pages) == 1
17988
            page = tif.pages.first
17989
            assert page.is_volumetric
17990
            assert page.is_tiled
17991
            assert page.compression == COMPRESSION.PNG
17992
            assert not page.is_contiguous
17993
            assert page.planarconfig == PLANARCONFIG.CONTIG
17994
            assert page.photometric == PHOTOMETRIC.RGB
17995
            assert page.imagewidth == 96
17996
            assert page.imagelength == 64
17997
            assert page.imagedepth == 16
17998
            assert page.tilewidth == 64
17999
            assert page.tilelength == 64
18000
            assert page.tiledepth == 1
18001
            assert page.samplesperpixel == 3
18002
            image = tif.asarray()
18003
            assert_array_equal(data, image)
18004
            assert_aszarr_method(tif, image)
18005
            assert__str__(tif)
18006

18007

18008
def test_write_volumetric_tiled_planar_rgb():
18009
    """Test write 5D array as grayscale volumes."""
18010
    shape = (2, 3, 256, 64, 96)
18011
    data = numpy.empty(shape, dtype=numpy.uint8)
18012
    data[:] = numpy.arange(256, dtype=numpy.uint8).reshape(1, 1, -1, 1, 1)
18013
    with TempFileName('write_volumetric_tiled_planar_rgb') as fname:
18014
        imwrite(
18015
            fname,
18016
            data,
18017
            tile=(256, 64, 96),
18018
            photometric=PHOTOMETRIC.RGB,
18019
            planarconfig=PLANARCONFIG.SEPARATE,
18020
        )
18021
        assert_valid_tiff(fname)
18022
        with TiffFile(fname) as tif:
18023
            assert len(tif.pages) == 2
18024
            page = tif.pages.first
18025
            assert page.is_volumetric
18026
            assert page.is_tiled
18027
            assert page.is_contiguous
18028
            assert page.planarconfig == PLANARCONFIG.SEPARATE
18029
            assert page.photometric == PHOTOMETRIC.RGB
18030
            assert page.imagewidth == 96
18031
            assert page.imagelength == 64
18032
            assert page.imagedepth == 256
18033
            assert page.tilewidth == 96
18034
            assert page.tilelength == 64
18035
            assert page.tiledepth == 256
18036
            assert page.samplesperpixel == 3
18037
            series = tif.series[0]
18038
            assert series.kind == 'shaped'
18039
            assert len(series._pages) == 1
18040
            assert len(series.pages) == 2
18041
            assert series.dataoffset is not None
18042
            assert series.shape == shape
18043
            image = tif.asarray()
18044
            assert_array_equal(data, image)
18045
            assert_aszarr_method(tif, image)
18046
            assert__str__(tif)
18047

18048

18049
def test_write_volumetric_tiled_contig_rgb():
18050
    """Test write 6D array as contig RGB volumes."""
18051
    shape = (2, 3, 256, 64, 96, 3)
18052
    data = numpy.empty(shape, dtype=numpy.uint8)
18053
    data[:] = numpy.arange(256, dtype=numpy.uint8).reshape(1, 1, -1, 1, 1, 1)
18054
    with TempFileName('write_volumetric_tiled_contig_rgb') as fname:
18055
        imwrite(fname, data, tile=(256, 64, 96), photometric=PHOTOMETRIC.RGB)
18056
        assert_valid_tiff(fname)
18057
        with TiffFile(fname) as tif:
18058
            assert len(tif.pages) == 6
18059
            page = tif.pages.first
18060
            assert page.is_volumetric
18061
            assert page.is_tiled
18062
            assert page.is_contiguous
18063
            assert page.planarconfig == PLANARCONFIG.CONTIG
18064
            assert page.photometric == PHOTOMETRIC.RGB
18065
            assert page.imagewidth == 96
18066
            assert page.imagelength == 64
18067
            assert page.imagedepth == 256
18068
            assert page.tilewidth == 96
18069
            assert page.tilelength == 64
18070
            assert page.tiledepth == 256
18071
            assert page.samplesperpixel == 3
18072
            # self.assertEqual(page.tags['TileOffsets'].value, (352,))
18073
            assert page.tags['TileByteCounts'].value == (4718592,)
18074
            series = tif.series[0]
18075
            assert series.kind == 'shaped'
18076
            assert len(series._pages) == 1
18077
            assert len(series.pages) == 6
18078
            assert series.dataoffset is not None
18079
            assert series.shape == shape
18080
            image = tif.asarray()
18081
            assert_array_equal(data, image)
18082
            # assert iterating over series.pages
18083
            data = data.reshape(6, 256, 64, 96, 3)
18084
            for i, page in enumerate(series.pages):
18085
                image = page.asarray()
18086
                assert_array_equal(data[i], image)
18087
                assert_aszarr_method(page, image)
18088
            assert__str__(tif)
18089

18090

18091
@pytest.mark.skipif(SKIP_LARGE, reason=REASON)
18092
def test_write_volumetric_tiled_contig_rgb_empty():
18093
    """Test write empty 6D array as contig RGB volumes."""
18094
    shape = (2, 3, 256, 64, 96, 3)
18095
    with TempFileName('write_volumetric_tiled_contig_rgb_empty') as fname:
18096
        with TiffWriter(fname) as tif:
18097
            tif.write(
18098
                shape=shape,
18099
                dtype=numpy.uint8,
18100
                tile=(256, 64, 96),
18101
                photometric=PHOTOMETRIC.RGB,
18102
            )
18103
        assert_valid_tiff(fname)
18104
        with TiffFile(fname) as tif:
18105
            assert len(tif.pages) == 6
18106
            page = tif.pages.first
18107
            assert page.is_volumetric
18108
            assert page.is_tiled
18109
            assert page.is_contiguous
18110
            assert page.planarconfig == PLANARCONFIG.CONTIG
18111
            assert page.photometric == PHOTOMETRIC.RGB
18112
            assert page.imagewidth == 96
18113
            assert page.imagelength == 64
18114
            assert page.imagedepth == 256
18115
            assert page.tilewidth == 96
18116
            assert page.tilelength == 64
18117
            assert page.tiledepth == 256
18118
            assert page.samplesperpixel == 3
18119
            # self.assertEqual(page.tags['TileOffsets'].value, (352,))
18120
            assert page.tags['TileByteCounts'].value == (4718592,)
18121
            series = tif.series[0]
18122
            assert series.kind == 'shaped'
18123
            assert len(series._pages) == 1
18124
            assert len(series.pages) == 6
18125
            assert series.dataoffset is not None
18126
            assert series.shape == shape
18127
            image = tif.asarray()
18128
            assert_array_equal(image.shape, shape)
18129
            assert_aszarr_method(tif, image)
18130
            assert__str__(tif)
18131

18132

18133
def test_write_volumetric_striped():
18134
    """Test write striped volume."""
18135
    data = random_data(numpy.uint8, (15, 63, 95))
18136
    with TempFileName('write_volumetric_striped') as fname:
18137
        imwrite(fname, data, volumetric=True)
18138
        assert_valid_tiff(fname)
18139
        with TiffFile(fname) as tif:
18140
            assert len(tif.pages) == 1
18141
            page = tif.pages.first
18142
            assert page.is_volumetric
18143
            assert not page.is_tiled
18144
            assert page.is_contiguous
18145
            assert page.planarconfig == PLANARCONFIG.CONTIG
18146
            assert page.photometric != PHOTOMETRIC.RGB
18147
            assert page.imagewidth == 95
18148
            assert page.imagelength == 63
18149
            assert page.imagedepth == 15
18150
            assert len(page.dataoffsets) == 15
18151
            assert len(page.databytecounts) == 15
18152
            assert page.samplesperpixel == 1
18153
            image = tif.asarray()
18154
            assert_array_equal(data, image)
18155
            assert_aszarr_method(tif, image)
18156
            assert__str__(tif)
18157

18158

18159
@pytest.mark.skipif(SKIP_CODECS, reason=REASON)
18160
def test_write_volumetric_striped_png():
18161
    """Test write tiled volume using an image compressor."""
18162
    data = random_data(numpy.uint8, (15, 63, 95, 3))
18163
    with TempFileName('write_volumetric_striped_png') as fname:
18164
        imwrite(
18165
            fname,
18166
            data,
18167
            photometric=PHOTOMETRIC.RGB,
18168
            volumetric=True,
18169
            rowsperstrip=32,
18170
            compression=COMPRESSION.PNG,
18171
        )
18172
        assert_valid_tiff(fname)
18173
        with TiffFile(fname) as tif:
18174
            assert len(tif.pages) == 1
18175
            page = tif.pages.first
18176
            assert page.is_volumetric
18177
            assert not page.is_tiled
18178
            assert page.compression == COMPRESSION.PNG
18179
            assert not page.is_contiguous
18180
            assert page.planarconfig == PLANARCONFIG.CONTIG
18181
            assert page.photometric == PHOTOMETRIC.RGB
18182
            assert page.imagewidth == 95
18183
            assert page.imagelength == 63
18184
            assert page.imagedepth == 15
18185
            assert page.samplesperpixel == 3
18186
            assert len(page.dataoffsets) == 30
18187
            assert len(page.databytecounts) == 30
18188
            image = tif.asarray()
18189
            assert_array_equal(data, image)
18190
            assert_aszarr_method(tif, image)
18191
            assert_aszarr_method(tif, image, chunkmode='page')
18192
            assert__str__(tif)
18193

18194

18195
def test_write_volumetric_striped_planar_rgb():
18196
    """Test write 5D array as grayscale volumes."""
18197
    shape = (2, 3, 15, 63, 96)
18198
    data = numpy.empty(shape, dtype=numpy.uint8)
18199
    data[:] = numpy.arange(15, dtype=numpy.uint8).reshape(1, 1, -1, 1, 1)
18200
    with TempFileName('write_volumetric_striped_planar_rgb') as fname:
18201
        imwrite(fname, data, volumetric=True, photometric=PHOTOMETRIC.RGB)
18202
        assert_valid_tiff(fname)
18203
        with TiffFile(fname) as tif:
18204
            assert len(tif.pages) == 2
18205
            page = tif.pages.first
18206
            assert page.is_volumetric
18207
            assert not page.is_tiled
18208
            assert page.is_contiguous
18209
            assert page.planarconfig == PLANARCONFIG.SEPARATE
18210
            assert page.photometric == PHOTOMETRIC.RGB
18211
            assert page.imagewidth == 96
18212
            assert page.imagelength == 63
18213
            assert page.imagedepth == 15
18214
            assert page.samplesperpixel == 3
18215
            assert len(page.dataoffsets) == 15 * 3
18216
            assert len(page.databytecounts) == 15 * 3
18217
            series = tif.series[0]
18218
            assert series.kind == 'shaped'
18219
            assert len(series._pages) == 1
18220
            assert len(series.pages) == 2
18221
            assert series.dataoffset is not None
18222
            assert series.shape == shape
18223
            image = tif.asarray()
18224
            assert_array_equal(data, image)
18225
            assert_aszarr_method(tif, image)
18226
            assert__str__(tif)
18227

18228

18229
def test_write_volumetric_striped_contig_rgb():
18230
    """Test write 6D array as contig RGB volumes."""
18231
    shape = (2, 3, 15, 63, 95, 3)
18232
    data = numpy.empty(shape, dtype=numpy.uint8)
18233
    data[:] = numpy.arange(15, dtype=numpy.uint8).reshape(1, 1, -1, 1, 1, 1)
18234
    with TempFileName('write_volumetric_striped_contig_rgb') as fname:
18235
        imwrite(fname, data, volumetric=True, photometric=PHOTOMETRIC.RGB)
18236
        assert_valid_tiff(fname)
18237
        with TiffFile(fname) as tif:
18238
            assert len(tif.pages) == 6
18239
            page = tif.pages.first
18240
            assert page.is_volumetric
18241
            assert not page.is_tiled
18242
            assert page.is_contiguous
18243
            assert page.planarconfig == PLANARCONFIG.CONTIG
18244
            assert page.photometric == PHOTOMETRIC.RGB
18245
            assert page.imagewidth == 95
18246
            assert page.imagelength == 63
18247
            assert page.imagedepth == 15
18248
            assert page.samplesperpixel == 3
18249
            assert len(page.dataoffsets) == 15
18250
            assert len(page.databytecounts) == 15
18251
            series = tif.series[0]
18252
            assert series.kind == 'shaped'
18253
            assert len(series._pages) == 1
18254
            assert len(series.pages) == 6
18255
            assert series.dataoffset is not None
18256
            assert series.shape == shape
18257
            image = tif.asarray()
18258
            assert_array_equal(data, image)
18259
            # assert iterating over series.pages
18260
            data = data.reshape((6, 15, 63, 95, 3))
18261
            for i, page in enumerate(series.pages):
18262
                image = page.asarray()
18263
                assert_array_equal(data[i], image)
18264
                assert_aszarr_method(page, image)
18265
            assert__str__(tif)
18266

18267

18268
@pytest.mark.skipif(SKIP_LARGE, reason=REASON)
18269
def test_write_volumetric_striped_contig_rgb_empty():
18270
    """Test write empty 6D array as contig RGB volumes."""
18271
    shape = (2, 3, 15, 63, 95, 3)
18272
    with TempFileName('write_volumetric_striped_contig_rgb_empty') as fname:
18273
        with TiffWriter(fname) as tif:
18274
            tif.write(
18275
                shape=shape,
18276
                dtype=numpy.uint8,
18277
                volumetric=True,
18278
                photometric=PHOTOMETRIC.RGB,
18279
            )
18280
        assert_valid_tiff(fname)
18281
        with TiffFile(fname) as tif:
18282
            assert len(tif.pages) == 6
18283
            page = tif.pages.first
18284
            assert page.is_volumetric
18285
            assert not page.is_tiled
18286
            assert page.is_contiguous
18287
            assert page.planarconfig == PLANARCONFIG.CONTIG
18288
            assert page.photometric == PHOTOMETRIC.RGB
18289
            assert page.imagewidth == 95
18290
            assert page.imagelength == 63
18291
            assert page.imagedepth == 15
18292
            assert page.samplesperpixel == 3
18293
            assert len(page.dataoffsets) == 15
18294
            assert len(page.databytecounts) == 15
18295
            series = tif.series[0]
18296
            assert series.kind == 'shaped'
18297
            assert len(series._pages) == 1
18298
            assert len(series.pages) == 6
18299
            assert series.dataoffset is not None
18300
            assert series.shape == shape
18301
            image = tif.asarray()
18302
            assert_array_equal(image.shape, shape)
18303
            assert_aszarr_method(tif, image)
18304
            assert__str__(tif)
18305

18306

18307
def test_write_contiguous():
18308
    """Test contiguous mode."""
18309
    data = random_data(numpy.uint8, (5, 4, 219, 301, 3))
18310
    with TempFileName('write_contiguous') as fname:
18311
        with TiffWriter(fname, bigtiff=True) as tif:
18312
            for i in range(data.shape[0]):
18313
                tif.write(
18314
                    data[i], contiguous=True, photometric=PHOTOMETRIC.RGB
18315
                )
18316
        # assert_jhove(fname)
18317
        with TiffFile(fname) as tif:
18318
            assert tif.is_bigtiff
18319
            assert len(tif.pages) == 20
18320
            # check metadata is updated in-place
18321
            assert tif.pages.first.tags[270].valueoffset < tif.pages[1].offset
18322
            for page in tif.pages:
18323
                assert page.is_contiguous
18324
                assert page.planarconfig == PLANARCONFIG.CONTIG
18325
                assert page.photometric == PHOTOMETRIC.RGB
18326
                assert page.imagewidth == 301
18327
                assert page.imagelength == 219
18328
                assert page.samplesperpixel == 3
18329
            image = tif.asarray()
18330
            assert_array_equal(data, image)
18331
            assert_aszarr_method(tif, image)
18332
            assert__str__(tif)
18333

18334

18335
@pytest.mark.skipif(SKIP_LARGE, reason=REASON)
18336
def test_write_3gb():
18337
    """Test write 3 GB non-BigTIFF file."""
18338
    # https://github.com/blink1073/tifffile/issues/47
18339
    data = numpy.empty((4096 - 32, 1024, 1024), dtype=numpy.uint8)
18340
    with TempFileName('write_3gb') as fname:
18341
        imwrite(fname, data)
18342
        del data
18343
        assert_valid_tiff(fname)
18344
        # assert file
18345
        with TiffFile(fname) as tif:
18346
            assert not tif.is_bigtiff
18347

18348

18349
@pytest.mark.skipif(SKIP_LARGE, reason=REASON)
18350
def test_write_6gb():
18351
    """Test write 6 GB non-BigTIFF file."""
18352
    # https://stackoverflow.com/questions/74930263
18353
    data = numpy.empty((2**16, 2**15, 3), dtype=numpy.uint8)
18354
    with TempFileName('write_6gb') as fname:
18355
        imwrite(
18356
            fname, data, bigtiff=False, photometric='rgb', rowsperstrip=2**15
18357
        )
18358
        del data
18359
        assert_valid_tiff(fname)
18360
        # assert file
18361
        with TiffFile(fname) as tif:
18362
            assert not tif.is_bigtiff
18363
            assert tif.pages.first.dataoffsets[1] > 2**16
18364
            assert tif.pages.first.databytecounts[1] == 3221225472
18365
            # image = tif.asarray()
18366
        # assert_array_equal(data, image)
18367

18368

18369
@pytest.mark.skipif(SKIP_LARGE, reason=REASON)
18370
def test_write_5GB_fails():
18371
    """Test data too large for non-BigTIFF file."""
18372
    # TiffWriter should fail without bigtiff parameter
18373
    data = numpy.empty((640, 1024, 1024), dtype=numpy.float64)
18374
    data[:] = numpy.arange(640, dtype=numpy.float64).reshape(-1, 1, 1)
18375
    with TempFileName('write_5GB_fails') as fname:
18376
        with pytest.raises(ValueError):
18377
            with TiffWriter(fname) as tif:
18378
                tif.write(data)
18379
    # TODO: test 'unclosed file' not in capsys
18380

18381

18382
@pytest.mark.skipif(SKIP_LARGE, reason=REASON)
18383
def test_write_5GB_bigtiff():
18384
    """Test write 5GB BigTiff file."""
18385
    data = numpy.empty((640, 1024, 1024), dtype=numpy.float64)
18386
    data[:] = numpy.arange(640, dtype=numpy.float64).reshape(-1, 1, 1)
18387
    with TempFileName('write_5GB_bigtiff') as fname:
18388
        # imwrite should use bigtiff for large data
18389
        imwrite(fname, data)
18390
        # assert_jhove(fname)
18391
        # assert file
18392
        with TiffFile(fname) as tif:
18393
            assert tif.is_bigtiff
18394
            assert len(tif.pages) == 640
18395
            page = tif.pages.first
18396
            assert page.is_contiguous
18397
            assert page.planarconfig == PLANARCONFIG.CONTIG
18398
            assert page.photometric != PHOTOMETRIC.RGB
18399
            assert page.imagewidth == 1024
18400
            assert page.imagelength == 1024
18401
            assert page.samplesperpixel == 1
18402
            image = tif.asarray(out='memmap')
18403
            assert_array_equal(data, image)
18404
            del image
18405
            del data
18406
            assert__str__(tif)
18407

18408

18409
@pytest.mark.parametrize('compression', [0, 6])
18410
@pytest.mark.parametrize('dtype', [numpy.uint8, numpy.uint16])
18411
def test_write_palette(dtype, compression):
18412
    """Test write palette images."""
18413
    dtype = numpy.dtype(dtype)
18414
    data = random_data(dtype, (3, 219, 301))
18415
    cmap = random_data(numpy.uint16, (3, 2 ** (data.itemsize * 8)))
18416
    with TempFileName(f'write_palette_{compression}{dtype}') as fname:
18417
        imwrite(
18418
            fname,
18419
            data,
18420
            colormap=cmap,
18421
            compression=COMPRESSION.ADOBE_DEFLATE if compression else None,
18422
            compressionargs={'level': compression} if compression else None,
18423
        )
18424
        assert_valid_tiff(fname)
18425
        with TiffFile(fname) as tif:
18426
            assert len(tif.pages) == 3
18427
            page = tif.pages.first
18428
            assert page.is_contiguous != bool(compression)
18429
            assert page.planarconfig == PLANARCONFIG.CONTIG
18430
            assert page.photometric == PHOTOMETRIC.PALETTE
18431
            assert page.imagewidth == 301
18432
            assert page.imagelength == 219
18433
            assert page.samplesperpixel == 1
18434
            for i, page in enumerate(tif.pages):
18435
                assert_array_equal(apply_colormap(data[i], cmap), page.asrgb())
18436
            assert__str__(tif)
18437

18438

18439
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
18440
def test_write_palette_django():
18441
    """Test write palette read from existing file."""
18442
    fname = private_file('django.tiff')
18443
    with TiffFile(fname) as tif:
18444
        page = tif.pages.first
18445
        assert page.photometric == PHOTOMETRIC.PALETTE
18446
        assert page.imagewidth == 320
18447
        assert page.imagelength == 480
18448
        data = page.asarray()  # .squeeze()  # UserWarning ...
18449
        cmap = page.colormap
18450
        assert__str__(tif)
18451
    with TempFileName('write_palette_django') as fname:
18452
        imwrite(
18453
            fname, data, colormap=cmap, compression=COMPRESSION.ADOBE_DEFLATE
18454
        )
18455
        assert_valid_tiff(fname)
18456
        with TiffFile(fname) as tif:
18457
            assert len(tif.pages) == 1
18458
            page = tif.pages.first
18459
            assert not page.is_contiguous
18460
            assert page.planarconfig == PLANARCONFIG.CONTIG
18461
            assert page.photometric == PHOTOMETRIC.PALETTE
18462
            assert page.imagewidth == 320
18463
            assert page.imagelength == 480
18464
            assert page.samplesperpixel == 1
18465
            image = page.asrgb(uint8=False)
18466
            assert_array_equal(apply_colormap(data, cmap), image)
18467
            assert__str__(tif)
18468

18469

18470
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
18471
def test_write_multiple_series():
18472
    """Test write multiple data into one file using various options."""
18473
    data1 = imread(private_file('ome/multi-channel-4D-series.ome.tif'))
18474
    image1 = imread(private_file('django.tiff'))
18475
    image2 = imread(private_file('horse-16bit-col-littleendian.tif'))
18476
    with TempFileName('write_multiple_series') as fname:
18477
        with TiffWriter(fname, bigtiff=False) as tif:
18478
            # series 0
18479
            tif.write(
18480
                image1,
18481
                compression=COMPRESSION.ADOBE_DEFLATE,
18482
                compressionargs={'level': 5},
18483
                description='Django',
18484
            )
18485
            # series 1
18486
            tif.write(image2, photometric=PHOTOMETRIC.RGB)
18487
            # series 2
18488
            tif.write(data1[0], metadata=dict(axes='TCZYX'))
18489
            for i in range(1, data1.shape[0]):
18490
                tif.write(data1[i], contiguous=True)
18491
            # series 3
18492
            tif.write(data1[0], contiguous=False)
18493
            # series 4
18494
            tif.write(data1[0, 0, 0], tile=(64, 64))
18495
            # series 5
18496
            tif.write(
18497
                image1,
18498
                compression=COMPRESSION.ADOBE_DEFLATE,
18499
                description='DEFLATE',
18500
            )
18501
        assert_valid_tiff(fname)
18502
        with TiffFile(fname) as tif:
18503
            assert len(tif.pages) == 124
18504
            assert len(tif.series) == 6
18505
            series = tif.series[0]
18506
            assert not series.dataoffset
18507
            assert series.axes == 'YX'
18508
            assert series.kind == 'shaped'
18509
            assert_array_equal(image1, series.asarray())
18510
            assert_aszarr_method(series, image1)
18511
            series = tif.series[1]
18512
            assert series.dataoffset
18513
            assert series.axes == 'YXS'
18514
            assert series.kind == 'shaped'
18515
            assert_array_equal(image2, series.asarray())
18516
            assert_aszarr_method(series, image2)
18517
            series = tif.series[2]
18518
            assert series.dataoffset
18519
            assert series.keyframe.is_contiguous
18520
            assert len(series) == 105
18521
            assert len(series.pages) == 105
18522
            assert isinstance(series[104], TiffPage)
18523
            assert len(series[range(105)]) == 105
18524
            assert len(series[slice(0, None, 2)]) == 53
18525
            with pytest.raises(TypeError):
18526
                assert series['1']
18527
            assert series.axes == 'TCZYX'
18528
            assert series.kind == 'shaped'
18529
            result = series.asarray(out='memmap')
18530
            assert_array_equal(data1, result)
18531
            assert_aszarr_method(series, data1)
18532
            assert tif.filehandle.path == result.filename
18533
            del result
18534
            series = tif.series[3]
18535
            assert series.dataoffset
18536
            assert series.axes == 'QQYX'
18537
            assert series.kind == 'shaped'
18538
            assert_array_equal(data1[0], series.asarray())
18539
            assert_aszarr_method(series, data1[0])
18540
            series = tif.series[4]
18541
            assert not series.dataoffset
18542
            assert series.axes == 'YX'
18543
            assert series.kind == 'shaped'
18544
            assert_array_equal(data1[0, 0, 0], series.asarray())
18545
            assert_aszarr_method(series, data1[0, 0, 0])
18546
            series = tif.series[5]
18547
            assert not series.dataoffset
18548
            assert series.axes == 'YX'
18549
            assert series.kind == 'shaped'
18550
            assert_array_equal(image1, series.asarray())
18551
            assert_aszarr_method(series, image1)
18552
            assert__str__(tif)
18553

18554
            # test TiffFile.asarray key and series parameters
18555
            assert_array_equal(image1, tif.asarray(key=0))
18556
            assert_array_equal(image1, tif.asarray(key=-1))
18557

18558
            assert_array_equal(image2, tif.asarray(key=[1]))
18559
            assert_array_equal(image2, tif.asarray(key=0, series=1))
18560
            assert_array_equal(
18561
                image2, tif.asarray(key=0, series=tif.series[1])
18562
            )
18563

18564
            assert_array_equal(
18565
                data1, tif.asarray(key=range(2, 107)).reshape(data1.shape)
18566
            )
18567

18568
            assert_array_equal(
18569
                data1,
18570
                tif.asarray(key=range(105), series=2).reshape(data1.shape),
18571
            )
18572

18573
            assert_array_equal(
18574
                data1,
18575
                tif.asarray(key=slice(None), series=2).reshape(data1.shape),
18576
            )
18577

18578
            assert_array_equal(
18579
                data1[0],
18580
                tif.asarray(key=slice(107, 122)).reshape(data1[0].shape),
18581
            )
18582

18583
            assert_array_equal(
18584
                data1[0].reshape(-1, 167, 439)[::2],
18585
                tif.asarray(key=slice(107, 122, 2)).reshape((-1, 167, 439)),
18586
            )
18587

18588
            with pytest.raises(RuntimeError):
18589
                tif.asarray(key=[0, 1])
18590

18591
            with pytest.raises(RuntimeError):
18592
                tif.asarray(key=[-3, -2])
18593

18594
        assert_array_equal(image1, imread(fname, key=0))
18595
        assert_array_equal(image1, imread(fname, key=-1))
18596
        assert_array_equal(image2, imread(fname, key=[1]))
18597
        assert_array_equal(
18598
            data1, imread(fname, key=range(2, 107)).reshape(data1.shape)
18599
        )
18600
        assert_array_equal(
18601
            data1, imread(fname, key=range(105), series=2).reshape(data1.shape)
18602
        )
18603
        assert_array_equal(
18604
            data1[0],
18605
            imread(fname, key=slice(107, 122)).reshape(data1[0].shape),
18606
        )
18607

18608

18609
@pytest.mark.skipif(
18610
    SKIP_CODECS or not imagecodecs.PNG.available, reason=REASON
18611
)
18612
def test_write_multithreaded():
18613
    """Test write large tiled multithreaded."""
18614
    data = (
18615
        numpy.arange(4001 * 6003 * 3)
18616
        .astype(numpy.uint8)
18617
        .reshape(4001, 6003, 3)
18618
    )
18619
    with TempFileName('write_multithreaded') as fname:
18620
        imwrite(fname, data, tile=(512, 512), compression='PNG', maxworkers=6)
18621
        # assert_valid_tiff(fname)
18622
        with TiffFile(fname) as tif:
18623
            assert len(tif.pages) == 1
18624
            page = tif.pages.first
18625
            assert not page.is_contiguous
18626
            assert page.compression == COMPRESSION.PNG
18627
            assert page.planarconfig == PLANARCONFIG.CONTIG
18628
            assert page.imagewidth == 6003
18629
            assert page.imagelength == 4001
18630
            assert page.samplesperpixel == 3
18631
            image = tif.asarray(maxworkers=6)
18632
            assert_array_equal(data, image)
18633
            assert_aszarr_method(tif, image)
18634
            assert__str__(tif)
18635

18636

18637
@pytest.mark.skipif(SKIP_ZARR, reason=REASON)
18638
def test_write_zarr():
18639
    """Test write to TIFF via Zarr interface."""
18640
    with TempFileName('write_zarr', ext='.ome.tif') as fname:
18641
        with TiffWriter(fname, bigtiff=True) as tif:
18642
            tif.write(
18643
                shape=(7, 5, 252, 244),
18644
                dtype=numpy.uint16,
18645
                tile=(64, 64),
18646
                subifds=2,
18647
            )
18648
            tif.write(
18649
                shape=(7, 5, 126, 122), dtype=numpy.uint16, tile=(64, 64)
18650
            )
18651
            tif.write(shape=(7, 5, 63, 61), dtype=numpy.uint16, tile=(32, 32))
18652
            tif.write(
18653
                shape=(3, 252, 244),
18654
                dtype=numpy.uint8,
18655
                photometric='RGB',
18656
                planarconfig='SEPARATE',
18657
                rowsperstrip=63,
18658
            )
18659
            tif.write(
18660
                shape=(252, 244, 3),
18661
                dtype=numpy.uint8,
18662
                photometric='RGB',
18663
                rowsperstrip=64,
18664
            )
18665
            tif.write(
18666
                numpy.zeros((252, 244, 3), numpy.uint8),
18667
                photometric='RGB',
18668
                rowsperstrip=252,
18669
                compression='zlib',
18670
            )
18671

18672
        with TiffFile(fname, mode='r+') as tif:
18673
            with tif.series[0].aszarr() as store:
18674
                z = zarr.open(store, mode='r+')
18675
                z[0][2, 2:3, 100:111, 100:200] = 100
18676
                z[1][3, 3:4, 100:111, 100:] = 101
18677
                z[2][4, 4:5, 33:40, 41:] = 102
18678
            assert tif.asarray(series=0)[2, 2, 100, 199] == 100
18679
            assert tif.asarray(series=0, level=1)[3, 3, 100, 121] == 101
18680
            assert tif.asarray(series=0, level=2)[4, 4, 33, 41] == 102
18681

18682
        with TiffFile(fname, mode='r+') as tif:
18683
            with tif.series[1].aszarr() as store:
18684
                z = zarr.open(store, mode='r+')
18685
                z[1, 100:111, 100:200] = 104
18686
            assert tif.series[1].asarray()[1, 100, 199] == 104
18687

18688
        with TiffFile(fname, mode='r+') as tif:
18689
            with tif.series[2].aszarr() as store:
18690
                z = zarr.open(store, mode='r+')
18691
                z[200:, 20:, 1] = 105
18692
            assert tif.series[2].asarray()[251, 243, 1] == 105
18693

18694
        with TiffFile(fname, mode='r+') as tif:
18695
            with tif.series[3].aszarr() as store:
18696
                z = zarr.open(store, mode='r+')
18697
                with pytest.raises(PermissionError):
18698
                    z[100, 20] = 106
18699

18700

18701
@pytest.mark.skipif(SKIP_ZARR, reason=REASON)
18702
def assert_fsspec(url, data, target_protocol='http'):
18703
    """Assert fsspec ReferenceFileSystem from local http server."""
18704
    mapper = fsspec.get_mapper(
18705
        'reference://', fo=url, target_protocol=target_protocol
18706
    )
18707
    zobj = zarr.open(mapper, mode='r')
18708
    if isinstance(zobj, zarr.Group):
18709
        assert_array_equal(zobj[0][:], data)
18710
        assert_array_equal(zobj[1][:], data[:, ::2, ::2])
18711
        assert_array_equal(zobj[2][:], data[:, ::4, ::4])
18712
    else:
18713
        assert_array_equal(zobj[:], data)
18714

18715

18716
@pytest.mark.skipif(
18717
    SKIP_HTTP or SKIP_ZARR or SKIP_CODECS or not imagecodecs.JPEG.available,
18718
    reason=REASON,
18719
)
18720
@pytest.mark.parametrize('byteorder', ['<', '>'])
18721
@pytest.mark.parametrize('version', [0, 1])
18722
def test_write_fsspec(version, byteorder):
18723
    """Test write fsspec for multi-series OME-TIFF."""
18724
    from imagecodecs.numcodecs import register_codecs
18725

18726
    register_codecs('imagecodecs_jpeg', verbose=False)
18727
    register_codecs('imagecodecs_delta', verbose=False)
18728
    register_codecs('imagecodecs_floatpred', verbose=False)
18729

18730
    data0 = random_data(numpy.uint8, (3, 252, 244))
18731
    data1 = random_data(numpy.uint8, (219, 301, 3))
18732
    data2 = random_data(numpy.uint16, (3, 219, 301))
18733
    data3 = random_data(numpy.float32, (210, 301))
18734

18735
    bo = {'>': 'be', '<': 'le'}[byteorder]
18736

18737
    with TempFileName(
18738
        f'write_fsspec_v{version}_{bo}', ext='.ome.tif'
18739
    ) as fname:
18740
        filename = os.path.split(fname)[-1]
18741
        with TiffWriter(fname, ome=True, byteorder=byteorder) as tif:
18742
            # series 0
18743
            options = dict(
18744
                tile=(64, 64),
18745
                photometric=PHOTOMETRIC.MINISBLACK,
18746
                compression=COMPRESSION.DEFLATE,
18747
                predictor=PREDICTOR.HORIZONTAL,
18748
            )
18749
            tif.write(data0, subifds=2, **options)
18750
            tif.write(data0[:, ::2, ::2], subfiletype=1, **options)
18751
            tif.write(data0[:, ::4, ::4], subfiletype=1, **options)
18752
            # series 1
18753
            tif.write(
18754
                data1, photometric=PHOTOMETRIC.RGB, rowsperstrip=data1.shape[0]
18755
            )
18756
            # series 2
18757
            tif.write(
18758
                data2,
18759
                rowsperstrip=data1.shape[1],
18760
                photometric=PHOTOMETRIC.RGB,
18761
                planarconfig=PLANARCONFIG.SEPARATE,
18762
                compression=COMPRESSION.DEFLATE,
18763
                predictor=PREDICTOR.HORIZONTAL,
18764
            )
18765
            # series 3
18766
            tif.write(data1, photometric=PHOTOMETRIC.RGB, rowsperstrip=5)
18767
            # series 4
18768
            tif.write(
18769
                data1,
18770
                photometric=PHOTOMETRIC.RGB,
18771
                tile=(32, 32),
18772
                compression=COMPRESSION.JPEG,
18773
            )
18774
            # series 5
18775
            tif.write(
18776
                data3,
18777
                rowsperstrip=105,
18778
                photometric=PHOTOMETRIC.MINISBLACK,
18779
                compression=COMPRESSION.DEFLATE,
18780
                predictor=PREDICTOR.FLOATINGPOINT,
18781
            )
18782

18783
        with TiffFile(fname) as tif:
18784
            assert tif.is_ome
18785
            assert len(tif.series) == 6
18786

18787
            # TODO: clean up temp JSON files
18788
            with tif.series[0].aszarr() as store:
18789
                assert store.is_multiscales
18790
                store.write_fsspec(
18791
                    fname + f'.v{version}.s0.json', URL, version=version
18792
                )
18793
            assert_array_equal(tif.series[0].asarray(), data0)
18794
            assert_fsspec(URL + filename + f'.v{version}.s0.json', data0)
18795

18796
            with tif.series[1].aszarr() as store:
18797
                assert not store.is_multiscales
18798
                store.write_fsspec(
18799
                    fname + f'.v{version}.s1.json', URL, version=version
18800
                )
18801
            assert_array_equal(tif.series[1].asarray(), data1)
18802
            assert_fsspec(URL + filename + f'.v{version}.s1.json', data1)
18803

18804
            with tif.series[2].aszarr() as store:
18805
                store.write_fsspec(
18806
                    fname + f'.v{version}.s2.json', URL, version=version
18807
                )
18808
            assert_array_equal(tif.series[2].asarray(), data2)
18809
            assert_fsspec(URL + filename + f'.v{version}.s2.json', data2)
18810

18811
            with tif.series[3].aszarr(chunkmode=2) as store:
18812
                store.write_fsspec(
18813
                    fname + f'.v{version}.s3.json', URL, version=version
18814
                )
18815
            assert_array_equal(tif.series[3].asarray(), data1)
18816
            assert_fsspec(URL + filename + f'.v{version}.s3.json', data1)
18817

18818
            with tif.series[3].aszarr() as store:
18819
                with pytest.raises(ValueError):
18820
                    # imagelength % rowsperstrip != 0
18821
                    store.write_fsspec(
18822
                        fname + f'.v{version}.s3fail.json',
18823
                        URL,
18824
                        version=version,
18825
                    )
18826

18827
            with tif.series[4].aszarr() as store:
18828
                store.write_fsspec(
18829
                    fname + f'.v{version}.s4.json', URL, version=version
18830
                )
18831
            assert_fsspec(
18832
                URL + filename + f'.v{version}.s4.json',
18833
                tif.series[4].asarray(),
18834
            )
18835

18836
            with tif.series[5].aszarr() as store:
18837
                store.write_fsspec(
18838
                    fname + f'.v{version}.s5.json', URL, version=version
18839
                )
18840
            assert_array_equal(tif.series[5].asarray(), data3)
18841
            assert_fsspec(URL + filename + f'.v{version}.s5.json', data3)
18842

18843

18844
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_ZARR, reason=REASON)
18845
@pytest.mark.parametrize('version', [0, 1])
18846
@pytest.mark.parametrize('chunkmode', [0, 2])
18847
def test_write_fsspec_multifile(version, chunkmode):
18848
    """Test write fsspec for multi-file OME series."""
18849
    fname = public_file('OME/multifile/multifile-Z1.ome.tiff')
18850
    url = os.path.dirname(fname).replace('\\', '/')
18851
    with TempFileName(
18852
        f'write_fsspec_multifile_{version}{chunkmode}', ext='.json'
18853
    ) as jsonfile:
18854
        # write to file handle
18855
        with open(jsonfile, 'w', encoding='utf-8') as fh:
18856
            with TiffFile(fname) as tif:
18857
                data = tif.series[0].asarray()
18858
                with tif.series[0].aszarr(chunkmode=chunkmode) as store:
18859
                    store.write_fsspec(
18860
                        fh, url=url, version=version, templatename='f'
18861
                    )
18862
        mapper = fsspec.get_mapper(
18863
            'reference://',
18864
            fo=jsonfile,
18865
            target_protocol='file',
18866
            remote_protocol='file',
18867
        )
18868
        zobj = zarr.open(mapper, mode='r')
18869
        assert_array_equal(zobj[:], data)
18870

18871

18872
@pytest.mark.skipif(
18873
    SKIP_PRIVATE or SKIP_LARGE or SKIP_CODECS or SKIP_ZARR,
18874
    reason=REASON,
18875
)
18876
@pytest.mark.parametrize('version', [1])  # 0,
18877
def test_write_fsspec_sequence(version):
18878
    """Test write fsspec for multi-file sequence."""
18879
    # https://bbbc.broadinstitute.org/BBBC006
18880
    categories = {'p': {chr(i + 97): i for i in range(25)}}
18881
    ptrn = r'(?:_(z)_(\d+)).*_(?P<p>[a-z])(?P<a>\d+)(?:_(s)(\d))(?:_(w)(\d))'
18882
    fnames = private_file('BBBC/BBBC006_v1_images_z_00/*.tif')
18883
    fnames += private_file('BBBC/BBBC006_v1_images_z_01/*.tif')
18884
    tifs = TiffSequence(
18885
        fnames,
18886
        imread=imagecodecs.imread,
18887
        pattern=ptrn,
18888
        axesorder=(1, 2, 0, 3, 4),
18889
        categories=categories,
18890
    )
18891
    assert len(tifs) == 3072
18892
    assert tifs.shape == (16, 24, 2, 2, 2)
18893
    assert tifs.axes == 'PAZSW'
18894
    data = tifs.asarray()
18895
    with TempFileName(
18896
        'write_fsspec_sequence', ext=f'.v{version}.json'
18897
    ) as fname:
18898
        with tifs.aszarr(codec=imagecodecs.tiff_decode) as store:
18899
            store.write_fsspec(
18900
                fname,
18901
                'file:///' + store._commonpath.replace('\\', '/'),
18902
                version=version,
18903
            )
18904
        mapper = fsspec.get_mapper(
18905
            'reference://', fo=fname, target_protocol='file'
18906
        )
18907

18908
        from imagecodecs.numcodecs import register_codecs
18909

18910
        register_codecs()
18911

18912
        za = zarr.open(mapper, mode='r')
18913
        assert_array_equal(za[:], data)
18914

18915

18916
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_ZARR, reason=REASON)
18917
def test_write_tiff2fsspec():
18918
    """Test tiff2fsspec function."""
18919
    fname = public_file('tifffile/multiscene_pyramidal.ome.tif')
18920
    url = os.path.dirname(fname).replace('\\', '/')
18921
    data = imread(fname, series=0, level=1, maxworkers=1)
18922
    with TempFileName('write_tiff2fsspec', ext='.json') as jsonfile:
18923
        tiff2fsspec(
18924
            fname,
18925
            url,
18926
            out=jsonfile,
18927
            series=0,
18928
            level=1,
18929
            version=0,
18930
        )
18931
        mapper = fsspec.get_mapper(
18932
            'reference://',
18933
            fo=jsonfile,
18934
            target_protocol='file',
18935
            remote_protocol='file',
18936
        )
18937
        zobj = zarr.open(mapper, mode='r')
18938
        assert_array_equal(zobj[:], data)
18939

18940
        with pytest.raises(ValueError):
18941
            tiff2fsspec(
18942
                fname,
18943
                url,
18944
                out=jsonfile,
18945
                series=0,
18946
                level=1,
18947
                version=0,
18948
                chunkmode=CHUNKMODE.PAGE,
18949
            )
18950

18951

18952
@pytest.mark.skipif(SKIP_ZARR, reason=REASON)
18953
def test_write_numcodecs():
18954
    """Test write Zarr with numcodecs.Tiff."""
18955
    from tifffile import numcodecs
18956

18957
    data = numpy.arange(256 * 256 * 3, dtype=numpy.uint16).reshape(256, 256, 3)
18958
    numcodecs.register_codec()
18959
    compressor = numcodecs.Tiff(
18960
        bigtiff=True,
18961
        photometric=PHOTOMETRIC.MINISBLACK,
18962
        planarconfig=PLANARCONFIG.CONTIG,
18963
        compression=COMPRESSION.ADOBE_DEFLATE,
18964
        compressionargs={'level': 5},
18965
        key=0,
18966
    )
18967
    with TempFileName('write_numcodecs', ext='.zarr') as fname:
18968
        z = zarr.open(
18969
            fname,
18970
            mode='w',
18971
            shape=(256, 256, 3),
18972
            chunks=(100, 100, 3),
18973
            dtype=numpy.uint16,
18974
            compressor=compressor,
18975
        )
18976
        z[:] = data
18977
        assert_array_equal(z[:], data)
18978

18979

18980
###############################################################################
18981

18982
# Test write ImageJ
18983

18984

18985
@pytest.mark.skipif(SKIP_EXTENDED, reason=REASON)
18986
@pytest.mark.parametrize(
18987
    'shape',
18988
    [
18989
        (219, 301, 1),
18990
        (219, 301, 2),
18991
        (219, 301, 3),
18992
        (219, 301, 4),
18993
        (219, 301, 5),
18994
        (1, 219, 301),
18995
        (2, 219, 301),
18996
        (3, 219, 301),
18997
        (4, 219, 301),
18998
        (5, 219, 301),
18999
        (4, 3, 219, 301),
19000
        (4, 219, 301, 3),
19001
        (3, 4, 219, 301),
19002
        (1, 3, 1, 219, 301),
19003
        (3, 1, 1, 219, 301),
19004
        (1, 3, 4, 219, 301),
19005
        (3, 1, 4, 219, 301),
19006
        (3, 4, 1, 219, 301),
19007
        (3, 4, 1, 219, 301, 3),
19008
        (2, 3, 4, 219, 301),
19009
        (4, 3, 2, 219, 301, 3),
19010
    ],
19011
)
19012
@pytest.mark.parametrize(
19013
    'dtype', [numpy.uint8, numpy.uint16, numpy.int16, numpy.float32]
19014
)
19015
@pytest.mark.parametrize('byteorder', ['>', '<'])
19016
def test_write_imagej(byteorder, dtype, shape):
19017
    """Test write ImageJ format."""
19018
    # TODO: test compression and bigtiff ?
19019
    dtype = numpy.dtype(dtype)
19020
    if dtype != numpy.uint8 and shape[-1] in {3, 4}:
19021
        pytest.xfail('ImageJ only supports uint8 RGB')
19022
    data = random_data(dtype, shape)
19023
    fname = 'write_imagej_{}_{}_{}'.format(
19024
        {'<': 'le', '>': 'be'}[byteorder], dtype, str(shape).replace(' ', '')
19025
    )
19026
    with TempFileName(fname) as fname:
19027
        imwrite(fname, data, byteorder=byteorder, imagej=True)
19028
        image = imread(fname)
19029
        assert_array_equal(data.squeeze(), image.squeeze())
19030
        # TODO: assert_aszarr_method
19031
        assert_valid_tiff(fname)
19032

19033

19034
def test_write_imagej_voxel_size():
19035
    """Test write ImageJ with xyz voxel size 2.6755x2.6755x3.9474 µm^3."""
19036
    data = numpy.zeros((4, 256, 256), dtype=numpy.float32)
19037
    data.shape = 4, 1, 256, 256
19038
    with TempFileName('write_imagej_voxel_size') as fname:
19039
        imwrite(
19040
            fname,
19041
            data,
19042
            imagej=True,
19043
            resolution=(0.373759, 0.373759),
19044
            metadata={'spacing': 3.947368, 'unit': 'um'},
19045
        )
19046
        with TiffFile(fname) as tif:
19047
            assert tif.is_imagej
19048
            ijmeta = tif.imagej_metadata
19049
            assert ijmeta is not None
19050
            assert 'unit' in ijmeta
19051
            assert ijmeta['unit'] == 'um'
19052
            series = tif.series[0]
19053
            assert series.kind == 'imagej'
19054
            assert series.axes == 'ZYX'
19055
            assert series.shape == (4, 256, 256)
19056
            assert series.get_axes(False) == 'TZCYXS'
19057
            assert series.get_shape(False) == (1, 4, 1, 256, 256, 1)
19058
            assert__str__(tif)
19059
        assert_valid_tiff(fname)
19060

19061

19062
def test_write_imagej_metadata():
19063
    """Test write additional ImageJ metadata."""
19064
    data = numpy.empty((4, 256, 256), dtype=numpy.uint16)
19065
    data[:] = numpy.arange(256 * 256, dtype=numpy.uint16).reshape(1, 256, 256)
19066
    with TempFileName('write_imagej_metadata') as fname:
19067
        imwrite(fname, data, imagej=True, metadata={'unit': 'um'})
19068
        with TiffFile(fname) as tif:
19069
            assert tif.is_imagej
19070
            assert tif.imagej_metadata is not None
19071
            assert 'unit' in tif.imagej_metadata
19072
            assert tif.imagej_metadata['unit'] == 'um'
19073
            assert__str__(tif)
19074
        assert_valid_tiff(fname)
19075

19076

19077
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
19078
def test_write_imagej_ijmetadata_tag():
19079
    """Test write and read IJMetadata tag."""
19080
    fname = private_file('imagej/IJMetadata.tif')
19081
    with TiffFile(fname) as tif:
19082
        assert tif.is_imagej
19083
        assert tif.byteorder == '>'
19084
        assert len(tif.pages) == 3
19085
        assert len(tif.series) == 1
19086
        data = tif.asarray()
19087
        ijmeta = tif.pages.first.tags['IJMetadata'].value
19088

19089
    assert ijmeta['Info'][:21] == 'FluorescentCells.tif\n'
19090
    assert ijmeta['ROI'][:5] == b'Iout\x00'
19091
    assert ijmeta['Overlays'][1][:5] == b'Iout\x00'
19092
    assert ijmeta['Ranges'] == (0.0, 255.0, 0.0, 255.0, 0.0, 255.0)
19093
    assert ijmeta['Labels'] == ['Red', 'Green', 'Blue']
19094
    assert ijmeta['LUTs'][2][2, 255] == 255
19095
    assert_valid_tiff(fname)
19096

19097
    with TempFileName('write_imagej_ijmetadata') as fname:
19098
        with pytest.raises(TypeError):
19099
            imwrite(
19100
                fname,
19101
                data,
19102
                byteorder='>',
19103
                imagej=True,
19104
                metadata={'mode': 'composite'},
19105
                ijmetadata=ijmeta,
19106
            )
19107

19108
        imwrite(
19109
            fname,
19110
            data,
19111
            byteorder='>',
19112
            imagej=True,
19113
            metadata={**ijmeta, 'mode': 'composite'},
19114
        )
19115
        with TiffFile(fname) as tif:
19116
            assert tif.is_imagej
19117
            assert tif.byteorder == '>'
19118
            assert len(tif.pages) == 3
19119
            assert len(tif.series) == 1
19120
            imagej_metadata = tif.imagej_metadata
19121
            data2 = tif.asarray()
19122
            ijmeta2 = tif.pages.first.tags['IJMetadata'].value
19123

19124
            assert__str__(tif)
19125

19126
    assert_array_equal(data, data2)
19127
    assert imagej_metadata is not None
19128
    assert imagej_metadata['mode'] == 'composite'
19129
    assert imagej_metadata['Info'] == ijmeta['Info']
19130
    assert ijmeta2['Info'] == ijmeta['Info']
19131
    assert ijmeta2['ROI'] == ijmeta['ROI']
19132
    assert ijmeta2['Overlays'] == ijmeta['Overlays']
19133
    assert ijmeta2['Ranges'] == ijmeta['Ranges']
19134
    assert ijmeta2['Labels'] == ijmeta['Labels']
19135
    assert_array_equal(ijmeta2['LUTs'][2], ijmeta['LUTs'][2])
19136
    assert_valid_tiff(fname)
19137

19138

19139
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
19140
def test_write_imagej_roundtrip():
19141
    """Test ImageJ metadata survive read/write roundtrip."""
19142
    fname = private_file('imagej/IJMetadata.tif')
19143
    with TiffFile(fname) as tif:
19144
        assert tif.is_imagej
19145
        assert tif.byteorder == '>'
19146
        assert len(tif.pages) == 3
19147
        assert len(tif.series) == 1
19148
        data = tif.asarray()
19149
        ijmeta = tif.imagej_metadata
19150

19151
    assert ijmeta is not None
19152
    assert ijmeta['Info'][:21] == 'FluorescentCells.tif\n'
19153
    assert ijmeta['ROI'][:5] == b'Iout\x00'
19154
    assert ijmeta['Overlays'][1][:5] == b'Iout\x00'
19155
    assert ijmeta['Ranges'] == (0.0, 255.0, 0.0, 255.0, 0.0, 255.0)
19156
    assert ijmeta['Labels'] == ['Red', 'Green', 'Blue']
19157
    assert ijmeta['LUTs'][2][2, 255] == 255
19158
    assert ijmeta['mode'] == 'composite'
19159
    assert not ijmeta['loop']
19160
    assert ijmeta['ImageJ'] == '1.52b'
19161
    assert_valid_tiff(fname)
19162

19163
    with TempFileName('write_imagej_ijmetadata_roundtrip') as fname:
19164
        imwrite(fname, data, byteorder='>', imagej=True, metadata=ijmeta)
19165

19166
        with TiffFile(fname) as tif:
19167
            assert tif.is_imagej
19168
            assert tif.byteorder == '>'
19169
            assert len(tif.pages) == 3
19170
            assert len(tif.series) == 1
19171
            ijmeta2 = tif.imagej_metadata
19172
            data2 = tif.asarray()
19173
            assert__str__(tif)
19174

19175
    assert_array_equal(data, data2)
19176
    assert ijmeta2 is not None
19177
    assert ijmeta2['ImageJ'] == ijmeta['ImageJ']
19178
    assert ijmeta2['mode'] == ijmeta['mode']
19179
    assert ijmeta2['Info'] == ijmeta['Info']
19180
    assert ijmeta2['ROI'] == ijmeta['ROI']
19181
    assert ijmeta2['Overlays'] == ijmeta['Overlays']
19182
    assert ijmeta2['Ranges'] == ijmeta['Ranges']
19183
    assert ijmeta2['Labels'] == ijmeta['Labels']
19184
    assert_array_equal(ijmeta2['LUTs'][2], ijmeta['LUTs'][2])
19185
    assert_valid_tiff(fname)
19186

19187

19188
@pytest.mark.parametrize('mmap', [False, True])
19189
@pytest.mark.parametrize('truncate', [False, True])
19190
def test_write_imagej_hyperstack(truncate, mmap):
19191
    """Test write ImageJ hyperstack."""
19192
    shape = (5, 6, 7, 49, 61, 3)
19193
    data = numpy.empty(shape, dtype=numpy.uint8)
19194
    data[:] = numpy.arange(210, dtype=numpy.uint8).reshape(5, 6, 7, 1, 1, 1)
19195

19196
    _truncate = ['', '_trunc'][truncate]
19197
    _memmap = ['', '_memmap'][mmap]
19198
    with TempFileName(f'write_imagej_hyperstack{_truncate}{_memmap}') as fname:
19199
        if mmap:
19200
            image = memmap(
19201
                fname,
19202
                shape=data.shape,
19203
                dtype=data.dtype,
19204
                imagej=True,
19205
                truncate=truncate,
19206
            )
19207
            image[:] = data
19208
            del image
19209
        else:
19210
            imwrite(fname, data, truncate=truncate, imagej=True)
19211
        # assert file
19212
        with TiffFile(fname) as tif:
19213
            assert not tif.is_bigtiff
19214
            assert not tif.is_shaped
19215
            assert len(tif.pages) == 1 if truncate else 210
19216
            page = tif.pages.first
19217
            assert page.is_contiguous
19218
            assert page.planarconfig == PLANARCONFIG.CONTIG
19219
            assert page.photometric == PHOTOMETRIC.RGB
19220
            assert page.imagewidth == 61
19221
            assert page.imagelength == 49
19222
            assert page.samplesperpixel == 3
19223
            # assert series properties
19224
            series = tif.series[0]
19225
            assert series.is_truncated == truncate
19226
            assert series.kind == 'imagej'
19227
            assert series.shape == shape
19228
            assert len(series._pages) == 1
19229
            assert len(series.pages) == 1 if truncate else 210
19230
            assert series.dtype == numpy.uint8
19231
            assert series.axes == 'TZCYXS'
19232
            assert series.get_axes(False) == 'TZCYXS'
19233
            assert series.get_shape(False) == shape
19234
            # assert data
19235
            image = tif.asarray(out='memmap')
19236
            assert_array_equal(data.squeeze(), image.squeeze())
19237
            del image
19238
            # assert iterating over series.pages
19239
            data = data.reshape((210, 49, 61, 3))
19240
            for i, page in enumerate(series.pages):
19241
                image = page.asarray()
19242
                assert_array_equal(data[i], image)
19243
            del image
19244
            assert__str__(tif)
19245
        assert_valid_tiff(fname)
19246

19247

19248
def test_write_imagej_append():
19249
    """Test write ImageJ file consecutively."""
19250
    data = numpy.empty((256, 1, 256, 256), dtype=numpy.uint8)
19251
    data[:] = numpy.arange(256, dtype=numpy.uint8).reshape(-1, 1, 1, 1)
19252

19253
    with TempFileName('write_imagej_append') as fname:
19254
        with TiffWriter(fname, imagej=True) as tif:
19255
            for image in data:
19256
                tif.write(image, contiguous=True)
19257

19258
        assert_valid_tiff(fname)
19259

19260
        # assert file
19261
        with TiffFile(fname) as tif:
19262
            assert not tif.is_bigtiff
19263
            assert not tif.is_shaped
19264
            assert len(tif.pages) == 256
19265
            page = tif.pages.first
19266
            assert page.is_contiguous
19267
            assert page.planarconfig == PLANARCONFIG.CONTIG
19268
            assert page.photometric != PHOTOMETRIC.RGB
19269
            assert page.imagewidth == 256
19270
            assert page.imagelength == 256
19271
            assert page.samplesperpixel == 1
19272
            # assert series properties
19273
            series = tif.series[0]
19274
            assert series.kind == 'imagej'
19275
            assert series.shape == (256, 256, 256)
19276
            assert series.dtype == numpy.uint8
19277
            assert series.axes == 'ZYX'
19278
            assert series.get_axes(False) == 'TZCYXS'
19279
            assert series.get_shape(False) == (1, 256, 1, 256, 256, 1)
19280
            # assert data
19281
            image = tif.asarray(out='memmap')
19282
            assert_array_equal(data.squeeze(), image)
19283
            del image
19284
            assert__str__(tif)
19285

19286

19287
def test_write_imagej_bigtiff():
19288
    """Test write ImageJ BigTIFF with warning."""
19289
    with TempFileName('write_imagej_bigtiff') as fname:
19290
        with pytest.warns(UserWarning):
19291
            imwrite(
19292
                fname,
19293
                shape=(31, 33),
19294
                dtype=numpy.float32,
19295
                bigtiff=True,
19296
                imagej=True,
19297
                metadata=None,
19298
            )
19299

19300

19301
@pytest.mark.skipif(SKIP_LARGE, reason=REASON)
19302
def test_write_imagej_raw():
19303
    """Test write ImageJ 5 GB raw file."""
19304
    data = numpy.empty((1280, 1, 1024, 1024), dtype=numpy.float32)
19305
    data[:] = numpy.arange(1280, dtype=numpy.float32).reshape(-1, 1, 1, 1)
19306

19307
    with TempFileName('write_imagej_big') as fname:
19308
        with pytest.warns(UserWarning):
19309
            # UserWarning: truncating ImageJ file
19310
            imwrite(fname, data, imagej=True)
19311
        assert_valid_tiff(fname)
19312
        # assert file
19313
        with TiffFile(fname) as tif:
19314
            assert not tif.is_bigtiff
19315
            assert not tif.is_shaped
19316
            assert len(tif.pages) == 1
19317
            page = tif.pages.first
19318
            assert page.is_contiguous
19319
            assert page.planarconfig == PLANARCONFIG.CONTIG
19320
            assert page.photometric != PHOTOMETRIC.RGB
19321
            assert page.imagewidth == 1024
19322
            assert page.imagelength == 1024
19323
            assert page.samplesperpixel == 1
19324
            # assert series properties
19325
            series = tif.series[0]
19326
            assert series.kind == 'imagej'
19327
            assert len(series._pages) == 1
19328
            assert len(series.pages) == 1
19329
            assert series.shape == (1280, 1024, 1024)
19330
            assert series.dtype == numpy.float32
19331
            assert series.axes == 'ZYX'
19332
            assert series.get_axes(False) == 'TZCYXS'
19333
            assert series.get_shape(False) == (1, 1280, 1, 1024, 1024, 1)
19334
            # assert data
19335
            image = tif.asarray(out='memmap')
19336
            assert_array_equal(data.squeeze(), image.squeeze())
19337
            del image
19338

19339
            if not SKIP_ZARR:
19340
                store = imread(fname, aszarr=True)
19341
                try:
19342
                    z = zarr.open(store, mode='r')
19343
                    chunk = z[333:356, 99:513, 31:127]
19344
                finally:
19345
                    store.close()
19346
                assert_array_equal(chunk, data[333:356, 0, 99:513, 31:127])
19347

19348
                store = imread(fname, aszarr=True, chunkmode=2)
19349
                try:
19350
                    z = zarr.open(store, mode='r')
19351
                    chunk = z[333:356, 99:513, 31:127]
19352
                finally:
19353
                    store.close()
19354
                assert_array_equal(chunk, data[333:356, 0, 99:513, 31:127])
19355

19356
            assert__str__(tif)
19357

19358

19359
@pytest.mark.skipif(SKIP_EXTENDED, reason=REASON)
19360
@pytest.mark.parametrize(
19361
    'shape, axes',
19362
    [
19363
        ((219, 301, 1), None),
19364
        ((219, 301, 2), None),
19365
        ((219, 301, 3), None),
19366
        ((219, 301, 4), None),
19367
        ((219, 301, 5), None),
19368
        ((1, 219, 301), None),
19369
        ((2, 219, 301), None),
19370
        ((3, 219, 301), None),
19371
        ((4, 219, 301), None),
19372
        ((5, 219, 301), None),
19373
        ((4, 3, 219, 301), None),
19374
        ((4, 219, 301, 3), None),
19375
        ((3, 4, 219, 301), None),
19376
        ((1, 3, 1, 219, 301), None),
19377
        ((3, 1, 1, 219, 301), None),
19378
        ((1, 3, 4, 219, 301), None),
19379
        ((3, 1, 4, 219, 301), None),
19380
        ((3, 4, 1, 219, 301), None),
19381
        ((3, 4, 1, 219, 301, 3), None),
19382
        ((2, 3, 4, 219, 301), None),
19383
        ((4, 3, 2, 219, 301, 3), None),
19384
        ((3, 33, 31), 'CYX'),
19385
        ((33, 31, 3), 'YXC'),
19386
        ((5, 1, 33, 31), 'CSYX'),
19387
        ((5, 1, 33, 31), 'ZCYX'),
19388
        ((2, 3, 4, 219, 301, 3), 'TCZYXS'),
19389
        ((10, 5, 63, 65), 'EPYX'),
19390
        ((2, 3, 4, 5, 6, 7, 33, 31, 3), 'TQCPZRYXS'),
19391
    ],
19392
)
19393
def test_write_ome(shape, axes):
19394
    """Test write OME-TIFF format."""
19395
    photometric = None
19396
    planarconfig = None
19397
    if shape[-1] in {3, 4}:
19398
        photometric = PHOTOMETRIC.RGB
19399
        planarconfig = PLANARCONFIG.CONTIG
19400
    elif shape[-3] in {3, 4}:
19401
        photometric = PHOTOMETRIC.RGB
19402
        planarconfig = PLANARCONFIG.SEPARATE
19403

19404
    metadata = {'axes': axes} if axes is not None else None
19405
    data = random_data(numpy.uint8, shape)
19406
    fname = 'write_ome_{}.ome'.format(str(shape).replace(' ', ''))
19407
    with TempFileName(fname) as fname:
19408
        imwrite(
19409
            fname,
19410
            data,
19411
            metadata=metadata,
19412
            photometric=photometric,
19413
            planarconfig=planarconfig,
19414
        )
19415
        with TiffFile(fname) as tif:
19416
            assert tif.is_ome
19417
            assert not tif.is_shaped
19418
            assert tif.series[0].kind == 'ome'
19419
            image = tif.asarray()
19420
            omexml = tif.ome_metadata
19421
            if axes:
19422
                if axes == 'CYX':
19423
                    axes = 'SYX'
19424
                elif axes == 'YXC':
19425
                    axes = 'YXS'
19426
                assert tif.series[0].axes == squeeze_axes(shape, axes)[1]
19427
            assert_array_equal(data.squeeze(), image.squeeze())
19428
            assert_aszarr_method(tif, image)
19429
            assert_valid_omexml(omexml)
19430
        assert_valid_tiff(fname)
19431

19432

19433
def test_write_ome_enable():
19434
    """Test OME-TIFF enabling."""
19435
    data = numpy.zeros((32, 32), dtype=numpy.uint8)
19436
    with TempFileName('write_ome_enable.ome') as fname:
19437
        imwrite(fname, data)
19438
        with TiffFile(fname) as tif:
19439
            assert tif.is_ome
19440
        imwrite(fname, data, description='not OME')
19441
        with TiffFile(fname) as tif:
19442
            assert not tif.is_ome
19443
        with pytest.warns(UserWarning):
19444
            imwrite(fname, data, description='not OME', ome=True)
19445
        with TiffFile(fname) as tif:
19446
            assert tif.is_ome
19447
        imwrite(fname, data, imagej=True)
19448
        with TiffFile(fname) as tif:
19449
            assert not tif.is_ome
19450
            assert tif.is_imagej
19451
        imwrite(fname, data, imagej=True, ome=True)
19452
        with TiffFile(fname) as tif:
19453
            assert tif.is_ome
19454
            assert not tif.is_imagej
19455

19456
    with TempFileName('write_ome_auto.tif') as fname:
19457
        imwrite(fname, data)
19458
        with TiffFile(fname) as tif:
19459
            assert not tif.is_ome
19460
        imwrite(fname, data, ome=True)
19461
        with TiffFile(fname) as tif:
19462
            assert tif.is_ome
19463

19464

19465
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
19466
@pytest.mark.parametrize(
19467
    'method', ['manual', 'copy', 'iter', 'compression', 'xml', 'dask']
19468
)
19469
def test_write_ome_methods(method):
19470
    """Test re-write OME-TIFF."""
19471
    # 4D (7 time points, 5 focal planes)
19472
    if method == 'dask' and SKIP_DASK:
19473
        pytest.skip('skip dask')
19474

19475
    fname = public_file('OME/bioformats-artificial/4D-series.ome.tiff')
19476
    with TiffFile(fname) as tif:
19477
        series = tif.series[0]
19478
        data = series.asarray()
19479
        dtype = data.dtype
19480
        shape = data.shape
19481
        axes = series.axes
19482
        omexml = tif.ome_metadata
19483
        if method == 'dask':
19484
            store = series.aszarr()
19485
            darr = dask.array.from_zarr(store)
19486

19487
    def pages():
19488
        yield from data.reshape(-1, *data.shape[-2:])
19489

19490
    with TempFileName(f'write_ome_{method}.ome') as fname:
19491
        if method == 'xml':
19492
            # use original XML metadata
19493
            metadata = xml2dict(omexml)
19494
            metadata['axes'] = axes
19495
            imwrite(
19496
                fname,
19497
                data,
19498
                byteorder='>',
19499
                photometric=PHOTOMETRIC.MINISBLACK,
19500
                metadata=metadata,
19501
            )
19502

19503
        elif method == 'manual':
19504
            # manually write omexml to first page and data to individual pages
19505
            # process OME-XML
19506
            omexml = omexml.replace(
19507
                '4D-series.ome.tiff', os.path.split(fname)[-1]
19508
            )
19509
            # omexml = omexml.replace('BigEndian="true"', 'BigEndian="false"')
19510
            data = data.view(data.dtype.newbyteorder('>'))
19511
            # save image planes in the order referenced in the OME-XML
19512
            # make sure storage options (compression, byteorder, photometric)
19513
            #   match OME-XML
19514
            # write OME-XML to first page only
19515
            with TiffWriter(fname, byteorder='>') as tif:
19516
                for i, image in enumerate(pages()):
19517
                    description = omexml if i == 0 else None
19518
                    tif.write(
19519
                        image,
19520
                        description=description,
19521
                        photometric=PHOTOMETRIC.MINISBLACK,
19522
                        metadata=None,
19523
                        contiguous=False,
19524
                    )
19525

19526
        elif method == 'iter':
19527
            # use iterator over individual pages
19528
            imwrite(
19529
                fname,
19530
                pages(),
19531
                shape=shape,
19532
                dtype=dtype,
19533
                byteorder='>',
19534
                photometric=PHOTOMETRIC.MINISBLACK,
19535
                metadata={'axes': axes},
19536
            )
19537

19538
        elif method == 'compression':
19539
            # use iterator with compression
19540
            imwrite(
19541
                fname,
19542
                pages(),
19543
                shape=shape,
19544
                dtype=dtype,
19545
                byteorder='>',
19546
                photometric=PHOTOMETRIC.MINISBLACK,
19547
                compression=COMPRESSION.ADOBE_DEFLATE,
19548
                metadata={'axes': axes},
19549
            )
19550

19551
        elif method == 'copy':
19552
            # use one numpy array
19553
            imwrite(
19554
                fname,
19555
                data,
19556
                byteorder='>',
19557
                photometric=PHOTOMETRIC.MINISBLACK,
19558
                metadata={'axes': axes},
19559
            )
19560

19561
        elif method == 'dask':
19562
            # dask array
19563
            imwrite(
19564
                fname,
19565
                darr,
19566
                byteorder='>',
19567
                photometric=PHOTOMETRIC.MINISBLACK,
19568
                compression=COMPRESSION.ADOBE_DEFLATE,
19569
                metadata={'axes': axes},
19570
            )
19571
            del darr
19572
            store.close()
19573

19574
        with TiffFile(fname) as tif:
19575
            assert tif.is_ome
19576
            assert tif.byteorder == '>'
19577
            assert len(tif.pages) == 35
19578
            assert len(tif.series) == 1
19579
            # assert page properties
19580
            page = tif.pages.first
19581
            if method not in {'compression', 'dask'}:
19582
                assert page.is_contiguous
19583
                assert page.compression == COMPRESSION.NONE
19584
            assert page.imagewidth == 439
19585
            assert page.imagelength == 167
19586
            assert page.bitspersample == 8
19587
            assert page.samplesperpixel == 1
19588
            # assert series properties
19589
            series = tif.series[0]
19590
            assert series.kind == 'ome'
19591
            assert series.shape == (7, 5, 167, 439)
19592
            assert series.dtype == numpy.int8
19593
            assert series.axes == 'TZYX'
19594
            # assert data
19595
            assert_array_equal(data, tif.asarray())
19596
            assert_valid_omexml(tif.ome_metadata)
19597
            assert__str__(tif)
19598

19599
        assert_valid_tiff(fname)
19600

19601

19602
@pytest.mark.parametrize('contiguous', [True, False])
19603
def test_write_ome_manual(contiguous):
19604
    """Test write OME-TIFF manually."""
19605
    data = numpy.random.randint(0, 255, (19, 31, 21), numpy.uint8)
19606

19607
    with TempFileName(f'write_ome__manual{int(contiguous)}.ome') as fname:
19608
        with TiffWriter(fname) as tif:
19609
            # successively write image data to TIFF pages
19610
            # disable tifffile from writing any metadata
19611
            # add empty ImageDescription tag to first page
19612
            for i, frame in enumerate(data):
19613
                tif.write(
19614
                    frame,
19615
                    contiguous=contiguous,
19616
                    metadata=None,
19617
                    description=None if i else b'',
19618
                )
19619
            # update ImageDescription tag with custom OME-XML
19620
            xml = OmeXml()
19621
            xml.addimage(
19622
                numpy.uint8, (16, 31, 21), (16, 1, 1, 31, 21, 1), axes='ZYX'
19623
            )
19624
            xml.addimage(
19625
                numpy.uint8, (3, 31, 21), (3, 1, 1, 31, 21, 1), axes='CYX'
19626
            )
19627
            tif.overwrite_description(xml.tostring())
19628

19629
        with TiffFile(fname) as tif:
19630
            assert tif.is_ome
19631
            assert len(tif.pages) == 19
19632
            assert len(tif.series) == 2
19633
            # assert series properties
19634
            series = tif.series[0]
19635
            assert series.kind == 'ome'
19636
            assert series.axes == 'ZYX'
19637
            assert bool(series.dataoffset) == contiguous
19638
            assert_array_equal(data[:16], series.asarray())
19639
            series = tif.series[1]
19640
            assert series.kind == 'ome'
19641
            assert series.axes == 'CYX'
19642
            assert bool(series.dataoffset) == contiguous
19643
            assert_array_equal(data[16:], series.asarray())
19644
            #
19645
            assert_valid_omexml(tif.ome_metadata)
19646
            assert__str__(tif)
19647

19648
        assert_valid_tiff(fname)
19649

19650

19651
@pytest.mark.skipif(
19652
    SKIP_PUBLIC or SKIP_CODECS or not imagecodecs.JPEG.available,
19653
    reason=REASON,
19654
)
19655
def test_rewrite_ome():
19656
    """Test rewrite multi-series, pyramidal OME-TIFF."""
19657
    # https://github.com/cgohlke/tifffile/issues/156
19658
    # - data loss in case of JPEG recompression; copy tiles verbatim
19659
    # - OME metadata not copied; use ometypes library after writing
19660
    # - tifffile does not support multi-file OME-TIFF writing
19661
    fname = public_file('tifffile/multiscene_pyramidal.ome.tif')
19662
    with TiffFile(fname) as tif:
19663
        assert tif.is_ome
19664
        with TempFileName('rewrite_ome', ext='.ome.tif') as fname_copy:
19665
            with TiffWriter(
19666
                fname_copy,
19667
                bigtiff=tif.is_bigtiff,
19668
                byteorder=tif.byteorder,
19669
                ome=tif.is_ome,
19670
            ) as copy:
19671
                for series in tif.series:
19672
                    subifds = len(series.levels) - 1
19673
                    metadata = {'axes': series.axes}
19674
                    for level in series.levels:
19675
                        keyframe = level.keyframe
19676
                        copy.write(
19677
                            level.asarray(),
19678
                            planarconfig=keyframe.planarconfig,
19679
                            photometric=keyframe.photometric,
19680
                            extrasamples=keyframe.extrasamples,
19681
                            tile=keyframe.tile,
19682
                            rowsperstrip=keyframe.rowsperstrip,
19683
                            compression=keyframe.compression,
19684
                            predictor=keyframe.predictor,
19685
                            subsampling=keyframe.subsampling,
19686
                            datetime=keyframe.datetime,
19687
                            resolution=keyframe.resolution,
19688
                            resolutionunit=keyframe.resolutionunit,
19689
                            subfiletype=keyframe.subfiletype,
19690
                            colormap=keyframe.colormap,
19691
                            iccprofile=keyframe.iccprofile,
19692
                            subifds=subifds,
19693
                            metadata=metadata,
19694
                        )
19695
                        subifds = None
19696
                        metadata = None
19697
            # verify
19698
            with TiffFile(fname_copy) as copy:
19699
                assert copy.byteorder == tif.byteorder
19700
                assert copy.is_bigtiff == tif.is_bigtiff
19701
                assert copy.is_imagej == tif.is_imagej
19702
                assert copy.is_ome == tif.is_ome
19703
                assert len(tif.series) == len(copy.series)
19704
                for series, series_copy in zip(tif.series, copy.series):
19705
                    assert len(series.levels) == len(series_copy.levels)
19706
                    metadata = {'axes': series.axes}
19707
                    for level, level_copy in zip(
19708
                        series.levels, series_copy.levels
19709
                    ):
19710
                        assert len(level.pages) == len(level_copy.pages)
19711
                        assert level.shape == level_copy.shape
19712
                        assert level.dtype == level_copy.dtype
19713
                        assert level.keyframe.hash == level_copy.keyframe.hash
19714

19715

19716
@pytest.mark.skipif(
19717
    SKIP_PRIVATE
19718
    or SKIP_CODECS
19719
    or SKIP_LARGE
19720
    or not imagecodecs.JPEG.available,
19721
    reason=REASON,
19722
)
19723
def test_write_ome_copy():
19724
    """Test write pyramidal OME-TIFF by copying compressed tiles from SVS."""
19725

19726
    def tiles(page):
19727
        # return iterator over compressed tiles in page
19728
        assert page.is_tiled
19729
        fh = page.parent.filehandle
19730
        for offset, bytecount in zip(page.dataoffsets, page.databytecounts):
19731
            fh.seek(offset)
19732
            yield fh.read(bytecount)
19733

19734
    with TiffFile(private_file('AperioSVS/CMU-1.svs')) as svs:
19735
        assert svs.is_svs
19736
        levels = svs.series[0].levels
19737

19738
        with TempFileName('write_ome_copy', ext='.ome.tif') as fname:
19739
            with TiffWriter(fname, ome=True, bigtiff=True) as tif:
19740
                level = levels[0]
19741
                assert len(level.pages) == 1
19742
                page = level.pages[0]
19743
                if page.compression == 7:
19744
                    # override default that RGB will be compressed as YCBCR
19745
                    compressionargs = {'outcolorspace': page.photometric}
19746
                else:
19747
                    compressionargs = {}
19748
                extratags = (
19749
                    # copy some extra tags
19750
                    page.tags.get('ImageDepth').astuple(),  # this is ignored
19751
                    page.tags.get('InterColorProfile').astuple(),
19752
                )
19753
                tif.write(
19754
                    tiles(page),
19755
                    shape=page.shape,
19756
                    dtype=page.dtype,
19757
                    tile=page.tile,
19758
                    datetime=page.datetime,
19759
                    photometric=page.photometric,
19760
                    planarconfig=page.planarconfig,
19761
                    compression=page.compression,
19762
                    compressionargs=compressionargs,
19763
                    jpegtables=page.jpegtables,
19764
                    iccprofile=page.iccprofile,
19765
                    subsampling=page.subsampling,
19766
                    subifds=len(levels) - 1,
19767
                    extratags=extratags,
19768
                )
19769
                for level in levels[1:]:
19770
                    assert len(level.pages) == 1
19771
                    page = level.pages[0]
19772
                    if page.compression == 7:
19773
                        compressionargs = {'outcolorspace': page.photometric}
19774
                    else:
19775
                        compressionargs = {}
19776
                    tif.write(
19777
                        tiles(page),
19778
                        shape=page.shape,
19779
                        dtype=page.dtype,
19780
                        tile=page.tile,
19781
                        datetime=page.datetime,
19782
                        photometric=page.photometric,
19783
                        planarconfig=page.planarconfig,
19784
                        compression=page.compression,
19785
                        compressionargs=compressionargs,
19786
                        jpegtables=page.jpegtables,
19787
                        iccprofile=page.iccprofile,
19788
                        subsampling=page.subsampling,
19789
                        subfiletype=1,
19790
                    )
19791

19792
            with TiffFile(fname) as tif:
19793
                assert tif.is_ome
19794
                assert len(tif.pages) == 1
19795
                assert len(tif.pages.first.pages) == 2
19796
                assert 'InterColorProfile' in tif.pages.first.tags
19797
                assert 'ImageDepth' not in tif.pages.first.tags
19798
                assert tif.series[0].kind == 'ome'
19799
                levels_ = tif.series[0].levels
19800
                assert len(levels_) == len(levels)
19801
                for level, level_ in zip(levels[1:], levels_[1:]):
19802
                    assert level.shape == level_.shape
19803
                    assert level.dtype == level_.dtype
19804
                    assert_array_equal(level.asarray(), level_.asarray())
19805

19806

19807
@pytest.mark.skipif(
19808
    SKIP_PRIVATE or SKIP_CODECS or not imagecodecs.JPEG.available,
19809
    reason=REASON,
19810
)
19811
def test_write_geotiff_copy():
19812
    """Test write a copy of striped, compressed GeoTIFF."""
19813

19814
    def strips(page):
19815
        # return iterator over compressed strips in page
19816
        assert not page.is_tiled
19817
        fh = page.parent.filehandle
19818
        for offset, bytecount in zip(page.dataoffsets, page.databytecounts):
19819
            fh.seek(offset)
19820
            yield fh.read(bytecount)
19821

19822
    with TiffFile(private_file('GeoTIFF/ML_30m.tif')) as geotiff:
19823
        assert geotiff.is_geotiff
19824
        assert len(geotiff.pages) == 1
19825

19826
        with TempFileName('write_geotiff_copy') as fname:
19827
            with TiffWriter(
19828
                fname, byteorder=geotiff.byteorder, bigtiff=geotiff.is_bigtiff
19829
            ) as tif:
19830
                page = geotiff.pages[0]
19831
                tags = page.tags
19832
                extratags = (
19833
                    tags.get('ModelPixelScaleTag').astuple(),
19834
                    tags.get('ModelTiepointTag').astuple(),
19835
                    tags.get('GeoKeyDirectoryTag').astuple(),
19836
                    tags.get('GeoAsciiParamsTag').astuple(),
19837
                    tags.get('GDAL_NODATA').astuple(),
19838
                )
19839
                tif.write(
19840
                    strips(page),
19841
                    shape=page.shape,
19842
                    dtype=page.dtype,
19843
                    rowsperstrip=page.rowsperstrip,
19844
                    photometric=page.photometric,
19845
                    planarconfig=page.planarconfig,
19846
                    compression=page.compression,
19847
                    predictor=page.predictor,
19848
                    jpegtables=page.jpegtables,
19849
                    iccprofile=page.iccprofile,
19850
                    subsampling=page.subsampling,
19851
                    extratags=extratags,
19852
                )
19853

19854
            with TiffFile(fname) as tif:
19855
                assert tif.is_geotiff
19856
                assert len(tif.pages) == 1
19857
                page = tif.pages.first
19858
                assert page.nodata == -32767
19859
                assert page.tags['ModelPixelScaleTag'].value == (
19860
                    30.0,
19861
                    30.0,
19862
                    0.0,
19863
                )
19864
                assert page.tags['ModelTiepointTag'].value == (
19865
                    0.0,
19866
                    0.0,
19867
                    0.0,
19868
                    1769487.0,
19869
                    5439473.0,
19870
                    0.0,
19871
                )
19872
                assert tif.geotiff_metadata['GeogAngularUnitsGeoKey'] == 9102
19873
                assert_array_equal(tif.asarray(), geotiff.asarray())
19874

19875

19876
@pytest.mark.parametrize('ext', ['', 'b'])
19877
def test_write_open_mode(ext):
19878
    """Test TiffWriter with file open modes."""
19879
    data = numpy.random.randint(0, 255, (5, 31, 21), numpy.uint8)
19880
    with TempFileName('write_open_mode' + ext) as fname:
19881
        # write
19882
        imwrite(fname, data, mode='w' + ext)
19883
        assert_array_equal(imread(fname), data)
19884
        # exclusive creation
19885
        with pytest.raises(FileExistsError):
19886
            imwrite(fname, data, mode='x' + ext)
19887
        os.remove(fname)
19888
        imwrite(fname, data, mode='x' + ext)
19889
        assert_array_equal(imread(fname), data)
19890
        # append
19891
        imwrite(fname, data, mode='r+' + ext)
19892
        with TiffFile(fname) as tif:
19893
            assert len(tif.pages) == 10
19894
            assert len(tif.series) == 2
19895
            assert_array_equal(tif.series[0].asarray(), data)
19896
            assert_array_equal(tif.series[1].asarray(), data)
19897

19898
        # write to file handle
19899
        with FileHandle(fname, mode='w' + ext) as fh:
19900
            imwrite(fh, data, mode='ignored')
19901
        assert_array_equal(imread(fname), data)
19902
        # exclusive creation with file handle
19903
        with pytest.raises(FileExistsError):
19904
            with FileHandle(fname, mode='x' + ext) as fh:
19905
                pass
19906
        os.remove(fname)
19907
        with FileHandle(fname, mode='x' + ext) as fh:
19908
            imwrite(fh, data, mode='ignored' + ext)
19909
            assert not fh.closed
19910
            fh.seek(0)
19911
            with pytest.raises(OSError):  # io.UnsupportedOperation
19912
                fh.read(8)
19913
        assert_array_equal(imread(fname), data)
19914
        # append to file handle
19915
        with FileHandle(fname, mode='r+' + ext) as fh:
19916
            imwrite(fh, data, mode='ignored')
19917
            assert not fh.closed
19918
            fh.seek(0)
19919
            with TiffFile(fh) as tif:
19920
                assert len(tif.pages) == 10
19921
                assert len(tif.series) == 2
19922
                assert_array_equal(tif.series[0].asarray(), data)
19923
                assert_array_equal(tif.series[1].asarray(), data)
19924

19925
        with pytest.raises(ValueError):
19926
            imwrite(fname, data, mode=ext)
19927

19928
        with pytest.raises(ValueError):
19929
            imwrite(fname, data, mode='w' + ext, append=True)
19930

19931

19932
@pytest.mark.skipif(SKIP_ZARR or SKIP_DASK or SKIP_CODECS, reason=REASON)
19933
@pytest.mark.parametrize('atype', ['numpy', 'dask', 'zarr'])
19934
@pytest.mark.parametrize('compression', [None, 'zlib'])
19935
@pytest.mark.parametrize('tiled', [None, False, True])
19936
@pytest.mark.parametrize('byteorder', ['<', '>'])
19937
def test_write_array_types(atype, byteorder, tiled, compression):
19938
    """Test write array types."""
19939
    kwargs = {}
19940
    fname = f'write_{atype}_'
19941
    if tiled is None:
19942
        pass
19943
    elif tiled:
19944
        kwargs['tile'] = (64, 64)
19945
        fname += 'tiled_'
19946
    else:
19947
        kwargs['rowsperstrip'] = 64
19948
        fname += 'striped_'
19949
    if compression is not None:
19950
        kwargs['compression'] = compression
19951
        fname += compression
19952
    fname += 'be' if byteorder == '>' else 'le'
19953

19954
    data = numpy.random.randint(0, 1024, (3, 361, 254, 3), numpy.uint16)
19955
    if atype == 'numpy':
19956
        arr = data.copy()
19957
    elif atype == 'dask':
19958
        arr = dask.array.from_array(data, chunks=(1, 32, 64, 3))
19959
    elif atype == 'zarr':
19960
        arr = zarr.zeros(data.shape, chunks=(1, 32, 64, 3), dtype=data.dtype)
19961
        arr[:] = data
19962
    with TempFileName(fname) as fname:
19963
        imwrite(
19964
            fname,
19965
            arr[1:, 33 : 33 + 261, 31 : 31 + 200],
19966
            byteorder=byteorder,
19967
            **kwargs,
19968
        )
19969
        assert_array_equal(
19970
            imread(fname), data[1:, 33 : 33 + 261, 31 : 31 + 200]
19971
        )
19972
        assert_array_equal(
19973
            imagecodecs.imread(fname, index=None),
19974
            data[1:, 33 : 33 + 261, 31 : 31 + 200],
19975
        )
19976

19977

19978
###############################################################################
19979

19980
# Test embedded TIFF files
19981

19982
EMBED_NAME = public_file('tifffile/test_FileHandle.bin')
19983
EMBED_OFFSET = 7077
19984
EMBED_SIZE = 5744
19985
EMBED_OFFSET1 = 13820
19986
EMBED_SIZE1 = 7936382
19987

19988

19989
def assert_embed_tif(tif):
19990
    """Assert embedded TIFF file."""
19991
    # 4 series in 6 pages
19992
    assert tif.byteorder == '<'
19993
    assert len(tif.pages) == 6
19994
    assert len(tif.series) == 4
19995
    # assert series 0 properties
19996
    series = tif.series[0]
19997
    assert series.shape == (3, 20, 20)
19998
    assert series.dtype == numpy.uint8
19999
    assert series.axes == 'IYX'
20000
    assert series.kind == 'generic'
20001
    page = series.pages[0]
20002
    assert page.compression == COMPRESSION.LZW
20003
    assert page.imagewidth == 20
20004
    assert page.imagelength == 20
20005
    assert page.bitspersample == 8
20006
    assert page.samplesperpixel == 1
20007
    data = tif.asarray(series=0)
20008
    assert isinstance(data, numpy.ndarray)
20009
    assert data.shape == (3, 20, 20)
20010
    assert data.dtype == numpy.uint8
20011
    assert tuple(data[:, 9, 9]) == (19, 90, 206)
20012
    # assert series 1 properties
20013
    series = tif.series[1]
20014
    assert series.shape == (10, 10, 3)
20015
    assert series.dtype == numpy.float32
20016
    assert series.axes == 'YXS'
20017
    assert series.kind == 'generic'
20018
    page = series.pages[0]
20019
    assert page.photometric == PHOTOMETRIC.RGB
20020
    assert page.compression == COMPRESSION.LZW
20021
    assert page.imagewidth == 10
20022
    assert page.imagelength == 10
20023
    assert page.bitspersample == 32
20024
    assert page.samplesperpixel == 3
20025
    data = tif.asarray(series=1)
20026
    assert isinstance(data, numpy.ndarray)
20027
    assert data.shape == (10, 10, 3)
20028
    assert data.dtype == numpy.float32
20029
    assert round(abs(data[9, 9, 1] - 214.5733642578125), 7) == 0
20030
    # assert series 2 properties
20031
    series = tif.series[2]
20032
    assert series.shape == (20, 20, 3)
20033
    assert series.dtype == numpy.uint8
20034
    assert series.axes == 'YXS'
20035
    assert series.kind == 'generic'
20036
    page = series.pages[0]
20037
    assert page.photometric == PHOTOMETRIC.RGB
20038
    assert page.compression == COMPRESSION.LZW
20039
    assert page.imagewidth == 20
20040
    assert page.imagelength == 20
20041
    assert page.bitspersample == 8
20042
    assert page.samplesperpixel == 3
20043
    data = tif.asarray(series=2)
20044
    assert isinstance(data, numpy.ndarray)
20045
    assert data.shape == (20, 20, 3)
20046
    assert data.dtype == numpy.uint8
20047
    assert tuple(data[9, 9, :]) == (19, 90, 206)
20048
    # assert series 3 properties
20049
    series = tif.series[3]
20050
    assert series.shape == (10, 10)
20051
    assert series.dtype == numpy.float32
20052
    assert series.axes == 'YX'
20053
    assert series.kind == 'generic'
20054
    page = series.pages[0]
20055
    assert page.compression == COMPRESSION.LZW
20056
    assert page.imagewidth == 10
20057
    assert page.imagelength == 10
20058
    assert page.bitspersample == 32
20059
    assert page.samplesperpixel == 1
20060
    data = tif.asarray(series=3)
20061
    assert isinstance(data, numpy.ndarray)
20062
    assert data.shape == (10, 10)
20063
    assert data.dtype == numpy.float32
20064
    assert round(abs(data[9, 9] - 223.1648712158203), 7) == 0
20065
    assert__str__(tif)
20066

20067

20068
def assert_embed_micromanager(tif):
20069
    """Assert embedded MicroManager TIFF file."""
20070
    assert tif.is_ome
20071
    assert tif.is_imagej
20072
    assert tif.is_micromanager
20073
    assert tif.byteorder == '<'
20074
    assert len(tif.pages) == 15
20075
    assert len(tif.series) == 1
20076
    # assert non-tiff micromanager_metadata
20077
    assert tif.micromanager_metadata is not None
20078
    tags = tif.micromanager_metadata['Summary']
20079
    assert tags['MicroManagerVersion'] == '1.4.x dev'
20080
    assert tags['UserName'] == 'trurl'
20081
    # assert page properties
20082
    page = tif.pages.first
20083
    assert page.is_contiguous
20084
    assert page.compression == COMPRESSION.NONE
20085
    assert page.imagewidth == 512
20086
    assert page.imagelength == 512
20087
    assert page.bitspersample == 16
20088
    assert page.samplesperpixel == 1
20089
    # two description tags
20090
    assert page.description.startswith('<?xml')
20091
    assert page.description1.startswith('ImageJ')
20092
    # assert some metadata
20093
    ijmeta = tif.imagej_metadata
20094
    assert ijmeta is not None
20095
    assert ijmeta is not None
20096
    assert ijmeta['frames'] == 5
20097
    assert ijmeta['slices'] == 3
20098
    assert ijmeta['Ranges'] == (706.0, 5846.0)
20099
    tags = tif.pages.first.tags[51123].value
20100
    assert tags['FileName'] == 'Untitled_1_MMStack.ome.tif'
20101
    assert tags['PixelType'] == 'GRAY16'
20102
    # assert series properties
20103
    series = tif.series[0]
20104
    assert series.shape == (5, 3, 512, 512)
20105
    assert series.dtype == numpy.uint16
20106
    assert series.axes == 'TZYX'
20107
    assert series.kind == 'mmstack'
20108
    # assert data
20109
    data = tif.asarray()
20110
    assert data.shape == (5, 3, 512, 512)
20111
    assert data.dtype == numpy.uint16
20112
    assert data[4, 2, 511, 511] == 1602
20113
    # assert memmap
20114
    data = tif.asarray(out='memmap')
20115
    assert isinstance(data, numpy.memmap)
20116
    assert data.shape == (5, 3, 512, 512)
20117
    assert data.dtype == numpy.dtype('<u2')
20118
    assert data[4, 2, 511, 511] == 1602
20119
    del data
20120
    assert__str__(tif)
20121

20122

20123
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_CODECS, reason=REASON)
20124
def test_embed_tif_filename():
20125
    """Test embedded TIFF from filename."""
20126
    with TiffFile(EMBED_NAME, offset=EMBED_OFFSET, size=EMBED_SIZE) as tif:
20127
        assert_embed_tif(tif)
20128

20129

20130
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_CODECS, reason=REASON)
20131
def test_embed_tif_openfile():
20132
    """Test embedded TIFF from file handle."""
20133
    with open(EMBED_NAME, 'rb') as fh:
20134
        with TiffFile(fh, offset=EMBED_OFFSET, size=EMBED_SIZE) as tif:
20135
            assert_embed_tif(tif)
20136

20137

20138
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_CODECS, reason=REASON)
20139
def test_embed_tif_openfile_seek():
20140
    """Test embedded TIFF from seeked file handle."""
20141
    with open(EMBED_NAME, 'rb') as fh:
20142
        fh.seek(EMBED_OFFSET)
20143
        with TiffFile(fh, size=EMBED_SIZE) as tif:
20144
            assert_embed_tif(tif)
20145

20146

20147
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_CODECS, reason=REASON)
20148
def test_embed_tif_filehandle():
20149
    """Test embedded TIFF from FileHandle."""
20150
    with FileHandle(EMBED_NAME, offset=EMBED_OFFSET, size=EMBED_SIZE) as fh:
20151
        with TiffFile(fh) as tif:
20152
            assert_embed_tif(tif)
20153

20154

20155
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_CODECS, reason=REASON)
20156
def test_embed_tif_bytesio():
20157
    """Test embedded TIFF from BytesIO."""
20158
    with open(EMBED_NAME, 'rb') as fh:
20159
        bytesio = BytesIO(fh.read())
20160
    with TiffFile(bytesio, offset=EMBED_OFFSET, size=EMBED_SIZE) as tif:
20161
        assert_embed_tif(tif)
20162

20163

20164
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
20165
def test_embed_mm_filename():
20166
    """Test embedded MicroManager TIFF from file name."""
20167
    with TiffFile(EMBED_NAME, offset=EMBED_OFFSET1, size=EMBED_SIZE1) as tif:
20168
        assert_embed_micromanager(tif)
20169

20170

20171
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
20172
def test_embed_mm_openfile():
20173
    """Test embedded MicroManager TIFF from file handle."""
20174
    with open(EMBED_NAME, 'rb') as fh:
20175
        with TiffFile(fh, offset=EMBED_OFFSET1, size=EMBED_SIZE1) as tif:
20176
            assert_embed_micromanager(tif)
20177

20178

20179
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
20180
def test_embed_mm_openfile_seek():
20181
    """Test embedded MicroManager TIFF from seeked file handle."""
20182
    with open(EMBED_NAME, 'rb') as fh:
20183
        fh.seek(EMBED_OFFSET1)
20184
        with TiffFile(fh, size=EMBED_SIZE1) as tif:
20185
            assert_embed_micromanager(tif)
20186

20187

20188
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
20189
def test_embed_mm_filehandle():
20190
    """Test embedded MicroManager TIFF from FileHandle."""
20191
    with FileHandle(EMBED_NAME, offset=EMBED_OFFSET1, size=EMBED_SIZE1) as fh:
20192
        with TiffFile(fh) as tif:
20193
            assert_embed_micromanager(tif)
20194

20195

20196
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
20197
def test_embed_mm_bytesio():
20198
    """Test embedded MicroManager TIFF from BytesIO."""
20199
    with open(EMBED_NAME, 'rb') as fh:
20200
        bytesio = BytesIO(fh.read())
20201
    with TiffFile(bytesio, offset=EMBED_OFFSET1, size=EMBED_SIZE1) as tif:
20202
        assert_embed_micromanager(tif)
20203

20204

20205
###############################################################################
20206

20207
# Test sequence of image files
20208

20209

20210
def test_sequence_stream_list():
20211
    """Test TiffSequence with list of ByteIO streams raises TypeError."""
20212
    data = numpy.random.rand(7, 9)
20213
    files = [BytesIO(), BytesIO()]
20214
    for buffer in files:
20215
        imwrite(buffer, data)
20216
    with pytest.raises(TypeError):
20217
        imread(files)
20218

20219

20220
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
20221
@pytest.mark.parametrize('case', [0, 1, 2, 3])
20222
def test_sequence_glob_pattern(case):
20223
    """Test TiffSequence with glob pattern without axes pattern."""
20224
    fname = private_file('TiffSequence/*.tif')
20225
    tifs = TiffSequence(fname, pattern=None)
20226
    assert len(tifs) == 10
20227
    assert tifs.shape == (10,)
20228
    assert tifs.axes == 'I'
20229
    data = tifs.asarray()
20230
    if case == 0:
20231
        data = tifs.asarray()
20232
    elif case == 1:
20233
        data = tifs.asarray(
20234
            chunkshape=(480, 640), chunkdtype=numpy.uint8, pattern=None, key=0
20235
        )
20236
    elif case == 2:
20237
        data = tifs.asarray(
20238
            imreadargs={'key': 0},
20239
            chunkshape=(480, 640),
20240
            chunkdtype=numpy.uint8,
20241
            pattern=None,
20242
            out_inplace=True,
20243
            out='memmap',
20244
        )
20245
    elif case == 3:
20246
        data = numpy.empty((10, 480, 640), dtype=numpy.uint8)
20247
        tifs.asarray(
20248
            chunkshape=(480, 640),
20249
            chunkdtype=numpy.uint8,
20250
            pattern=None,
20251
            out_inplace=True,
20252
            out=data,
20253
            key=0,
20254
        )
20255
    assert isinstance(data, numpy.ndarray)
20256
    assert data.flags['C_CONTIGUOUS']
20257
    assert data.shape == (10, 480, 640)
20258
    assert data.dtype == numpy.uint8
20259
    assert data[9, 256, 256] == 135
20260
    if not SKIP_ZARR:
20261
        with tifs.aszarr() as store:
20262
            assert_array_equal(data, zarr.open(store, mode='r'))
20263
    assert__repr__(tifs)
20264

20265

20266
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
20267
def test_sequence_name_list():
20268
    """Test TiffSequence with list of file names without pattern."""
20269
    fname = [
20270
        private_file('TiffSequence/AT3_1m4_01.tif'),
20271
        private_file('TiffSequence/AT3_1m4_10.tif'),
20272
    ]
20273
    tifs = TiffSequence(fname, pattern=None)
20274
    assert len(tifs) == 2
20275
    assert tifs.shape == (2,)
20276
    assert tifs.axes == 'I'
20277
    data = tifs.asarray()
20278
    assert isinstance(data, numpy.ndarray)
20279
    assert data.flags['C_CONTIGUOUS']
20280
    assert data.shape == (2, 480, 640)
20281
    assert data.dtype == numpy.uint8
20282
    assert data[1, 256, 256] == 135
20283
    if not SKIP_ZARR:
20284
        with tifs.aszarr() as store:
20285
            assert_array_equal(data, zarr.open(store, mode='r'))
20286
    assert__repr__(tifs)
20287

20288

20289
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
20290
def test_sequence_oif_series():
20291
    """Test TiffSequence with files from Olympus OIF, memory mapped."""
20292
    fname = private_file(
20293
        'oif/MB231cell1_paxgfp_PDMSgasket_PMMAflat_30nm_378sli.oif.files/*.tif'
20294
    )
20295
    tifs = TiffSequence(fname, pattern='axes')
20296
    assert len(tifs) == 756
20297
    assert tifs.shape == (2, 378)
20298
    assert tifs.axes == 'CZ'
20299
    # memory map
20300
    data = tifs.asarray(out='memmap', ioworkers=None)
20301
    assert isinstance(data, numpy.memmap)
20302
    assert data.flags['C_CONTIGUOUS']
20303
    assert data.shape == (2, 378, 256, 256)
20304
    assert data.dtype == numpy.dtype('<u2')
20305
    assert data[1, 377, 70, 146] == 29
20306
    if not SKIP_ZARR:
20307
        with tifs.aszarr() as store:
20308
            assert_array_equal(data, zarr.open(store, mode='r'))
20309
    del data
20310
    assert__repr__(tifs)
20311

20312

20313
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
20314
def test_sequence_leica_series():
20315
    """Test TiffSequence with Leica TIFF series, memory mapped."""
20316
    fname = private_file('leicaseries/Series019_*.tif')
20317
    tifs = TiffSequence(fname, pattern='axes')
20318
    assert len(tifs) == 46
20319
    assert tifs.shape == (46,)
20320
    assert tifs.axes == 'Y'
20321
    # memory map
20322
    data = tifs.asarray(out='memmap')
20323
    assert isinstance(data, numpy.memmap)
20324
    assert data.flags['C_CONTIGUOUS']
20325
    assert data.shape == (46, 512, 512, 3)
20326
    assert data.dtype == numpy.uint8
20327
    assert tuple(data[45, 256, 256]) == (93, 56, 56)
20328
    if not SKIP_ZARR:
20329
        with tifs.aszarr() as store:
20330
            assert_array_equal(data, zarr.open(store, mode='r'))
20331
    del data
20332

20333

20334
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
20335
def test_sequence_zip_container():
20336
    """Test TiffSequence with glob pattern without axes pattern."""
20337
    fname = private_file('TiffSequence.zip')
20338
    with TiffSequence('*.tif', container=fname, pattern=None) as tifs:
20339
        assert len(tifs) == 10
20340
        assert tifs.shape == (10,)
20341
        assert tifs.axes == 'I'
20342
        data = tifs.asarray(chunkshape=(480, 640), chunkdtype=numpy.uint8)
20343
        assert isinstance(data, numpy.ndarray)
20344
        assert data.flags['C_CONTIGUOUS']
20345
        assert data.shape == (10, 480, 640)
20346
        assert data.dtype == numpy.uint8
20347
        assert data[9, 256, 256] == 135
20348
    assert_array_equal(data, imread(container=fname))
20349

20350

20351
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_LARGE or SKIP_CODECS, reason=REASON)
20352
def test_sequence_wells_axesorder():
20353
    """Test FileSequence with well plates and axes reorder."""
20354
    # https://bbbc.broadinstitute.org/BBBC006
20355
    categories = {'p': {chr(i + 97): i for i in range(25)}}
20356
    ptrn = r'(?:_(z)_(\d+)).*_(?P<p>[a-z])(?P<a>\d+)(?:_(s)(\d))(?:_(w)(\d))'
20357
    fnames = private_file('BBBC/BBBC006_v1_images_z_00/*.tif')
20358
    fnames += private_file('BBBC/BBBC006_v1_images_z_01/*.tif')
20359
    tifs = TiffSequence(
20360
        fnames, pattern=ptrn, categories=categories, axesorder=(1, 2, 0, 3, 4)
20361
    )
20362
    assert len(tifs) == 3072
20363
    assert tifs.shape == (16, 24, 2, 2, 2)
20364
    assert tifs.axes == 'PAZSW'
20365
    data = tifs.asarray()
20366
    assert isinstance(data, numpy.ndarray)
20367
    assert data.flags['C_CONTIGUOUS']
20368
    assert data.shape == (16, 24, 2, 2, 2, 520, 696)
20369
    assert data.dtype == numpy.uint16
20370
    assert data[8, 12, 1, 0, 1, 256, 519] == 1579
20371
    if not SKIP_ZARR:
20372
        with tifs.aszarr() as store:
20373
            assert_array_equal(data, zarr.open(store, mode='r'))
20374

20375

20376
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_LARGE, reason=REASON)
20377
@pytest.mark.parametrize('tiled', [False, True])
20378
def test_sequence_tiled(tiled):
20379
    """Test FileSequence with tiled OME-TIFFs."""
20380
    # Dataset from https://github.com/tlambert03/tifffolder/issues/2
20381
    ptrn = re.compile(
20382
        r'\[(?P<U>\d+) x (?P<V>\d+)\].*(C)(\d+).*(Z)(\d+)', re.IGNORECASE
20383
    )
20384
    fnames = private_file('TiffSequenceTiled/*.tif', expand=False)
20385
    tifs = TiffSequence(fnames, pattern=ptrn)
20386
    assert len(tifs) == 60
20387
    assert tifs.shape == (2, 3, 2, 5)
20388
    assert tifs.axes == 'UVCZ'
20389
    tiled = {0: 0, 1: 1} if tiled else None
20390
    data = tifs.asarray(axestiled=tiled, is_ome=False)
20391
    assert isinstance(data, numpy.ndarray)
20392
    assert data.flags['C_CONTIGUOUS']
20393
    assert data.dtype == numpy.uint16
20394
    if tiled:
20395
        assert data.shape == (2, 5, 2 * 2560, 3 * 2160)
20396
        assert data[1, 3, 2560 + 1024, 2 * 2160 + 1024] == 596
20397
    else:
20398
        assert data.shape == (2, 3, 2, 5, 2560, 2160)
20399
        assert data[1, 2, 1, 3, 1024, 1024] == 596
20400
    if not SKIP_ZARR:
20401
        with tifs.aszarr(axestiled=tiled, is_ome=False) as store:
20402
            if tiled:
20403
                assert_array_equal(
20404
                    data[1, 3, 2048:3072],
20405
                    zarr.open(store, mode='r')[1, 3, 2048:3072],
20406
                )
20407
            else:
20408
                assert_array_equal(
20409
                    data[1, 2, 1, 3:5],
20410
                    zarr.open(store, mode='r')[1, 2, 1, 3:5],
20411
                )
20412

20413

20414
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
20415
def test_sequence_imread():
20416
    """Test TiffSequence with imagecodecs.imread."""
20417
    fname = private_file('PNG/*.png')
20418
    pngs = TiffSequence(fname, imread=imagecodecs.imread)
20419
    assert len(pngs) == 4
20420
    assert pngs.shape == (4,)
20421
    assert pngs.axes == 'I'
20422
    data = pngs.asarray(codec=imagecodecs.png_decode)
20423
    assert data.flags['C_CONTIGUOUS']
20424
    assert data.shape == (4, 200, 200)
20425
    assert data.dtype == numpy.uint16
20426
    if not SKIP_ZARR:
20427
        with pngs.aszarr(codec=imagecodecs.png_decode) as store:
20428
            assert_array_equal(data, zarr.open(store, mode='r'))
20429
    del data
20430

20431

20432
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
20433
def test_sequence_imread_glob():
20434
    """Test imread function with glob pattern."""
20435
    fname = private_file('TiffSequence/*.tif')
20436
    data = imread(
20437
        fname,
20438
        imreadargs={'key': 0},
20439
        chunkshape=(480, 640),
20440
        chunkdtype=numpy.uint8,
20441
    )
20442
    assert data.shape == (10, 480, 640)
20443
    if not SKIP_ZARR:
20444
        store = imread(
20445
            fname,
20446
            aszarr=True,
20447
            imreadargs={'key': 0},
20448
            chunkshape=(480, 640),
20449
            chunkdtype=numpy.uint8,
20450
        )
20451
        try:
20452
            assert_array_equal(data, zarr.open(store, mode='r'))
20453
        finally:
20454
            store.close()
20455

20456

20457
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_CODECS, reason=REASON)
20458
def test_sequence_imread_one():
20459
    """Test imread function with one item in sequence."""
20460
    fname = private_file('TiffSequence/AT3_1m4_01.tif')
20461
    assert_array_equal(imread([fname]), imread(fname))
20462

20463

20464
###############################################################################
20465

20466
# Test packages depending on tifffile
20467

20468

20469
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
20470
def test_dependent_roifile():
20471
    """Test roifile.ImagejRoi class."""
20472
    from roifile import ImagejRoi
20473

20474
    for roi in ImagejRoi.fromfile(private_file('imagej/IJMetadata.tif')):
20475
        assert roi == ImagejRoi.frombytes(roi.tobytes())
20476
        roi.coordinates()
20477
        str(roi)
20478

20479

20480
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
20481
def test_dependent_lfdfiles():
20482
    """Test lfdfiles conversion to TIFF."""
20483
    from lfdfiles import LfdFileSequence, SimfcsInt, SimfcsZ64
20484

20485
    filename = private_file('SimFCS/simfcs.Z64')
20486
    with TempFileName('depend_simfcsz_z64', ext='.tif') as outfile:
20487
        with SimfcsZ64(filename) as z64:
20488
            data = z64.asarray()
20489
            z64.totiff(outfile)
20490
        with TiffFile(outfile) as tif:
20491
            assert len(tif.pages) == 256
20492
            assert len(tif.series) == 1
20493
            assert tif.series[0].shape == (256, 256, 256)
20494
            assert tif.series[0].dtype == numpy.float32
20495
            assert_array_equal(data, tif.asarray())
20496

20497
    filename = private_file('SimFCS/gpint')
20498
    with LfdFileSequence(
20499
        filename + '/v*001.int',
20500
        pattern=r'v(?P<Channel>\d)(?P<Image>\d*).int',
20501
        imread=SimfcsInt,
20502
    ) as ims:
20503
        assert ims.axes == 'CI'
20504
        assert ims.asarray().shape == (2, 1, 256, 256)
20505

20506

20507
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
20508
def test_dependent_cmapfile():
20509
    """Test cmapfile.lsm2cmap."""
20510
    from cmapfile import CmapFile, lsm2cmap
20511

20512
    filename = private_file('LSM/3d_zfish_onephoton_zoom.lsm')
20513
    data = imread(filename)
20514
    with TempFileName('depend_cmapfile', ext='.cmap') as cmapfile:
20515
        lsm2cmap(filename, cmapfile, step=(1.0, 1.0, 20.0))
20516
        fname = os.path.join(
20517
            os.path.split(cmapfile)[0],
20518
            cmapfile.replace('.cmap', '.ch0000.cmap'),
20519
        )
20520
        with CmapFile(fname, mode='r') as cmap:
20521
            assert_array_equal(
20522
                cmap['map00000']['data00000'], data.squeeze()[:, 0, :, :]
20523
            )
20524

20525

20526
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
20527
def test_dependent_czifile():
20528
    """Test czifile.CziFile."""
20529
    # TODO: test LZW compressed czi file
20530
    from czifile import CziFile
20531

20532
    fname = private_file('czi/pollen.czi')
20533
    with CziFile(fname) as czi:
20534
        assert czi.shape == (1, 1, 104, 365, 364, 1)
20535
        assert czi.axes == 'TCZYX0'
20536
        # verify data
20537
        data = czi.asarray()
20538
        assert data.flags['C_CONTIGUOUS']
20539
        assert data.shape == (1, 1, 104, 365, 364, 1)
20540
        assert data.dtype == numpy.uint8
20541
        assert data[0, 0, 52, 182, 182, 0] == 10
20542

20543

20544
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_LARGE, reason=REASON)
20545
def test_dependent_czi2tif():
20546
    """Test czifile.czi2tif."""
20547
    from czifile.czifile import CziFile, czi2tif
20548

20549
    fname = private_file('CZI/pollen.czi')
20550
    with CziFile(fname) as czi:
20551
        metadata = czi.metadata()
20552
        data = czi.asarray().squeeze()
20553
    with TempFileName('depend_czi2tif') as tif:
20554
        czi2tif(fname, tif, bigtiff=False)
20555
        with TiffFile(tif) as t:
20556
            im = t.asarray()
20557
            assert t.pages[0].description == metadata
20558

20559
        assert_array_equal(im, data)
20560
        del im
20561
        del data
20562
        assert_valid_tiff(tif)
20563

20564

20565
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_LARGE, reason=REASON)
20566
def test_dependent_czi2tif_airy():
20567
    """Test czifile.czi2tif with AiryScan."""
20568
    from czifile.czifile import czi2tif
20569

20570
    fname = private_file('CZI/AiryscanSRChannel.czi')
20571
    with TempFileName('depend_czi2tif_airy') as tif:
20572
        czi2tif(fname, tif, verbose=True, truncate=True, bigtiff=False)
20573
        im = memmap(tif)
20574
        assert im.shape == (32, 6, 1680, 1680)
20575
        assert tuple(im[17, :, 1500, 1000]) == (95, 109, 3597, 0, 0, 0)
20576
        del im
20577
        assert_valid_tiff(tif)
20578

20579

20580
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
20581
def test_dependent_oiffile():
20582
    """Test oiffile.OifFile."""
20583
    from oiffile import OifFile
20584

20585
    fname = private_file(
20586
        'oib/MB231cell1_paxgfp_PDMSgasket_PMMAflat_30nm_378sli.oib'
20587
    )
20588
    with OifFile(fname) as oib:
20589
        assert oib.is_oib
20590
        tifs = oib.series[0]
20591
        assert len(tifs) == 756
20592
        assert tifs.shape == (2, 378)
20593
        assert tifs.axes == 'CZ'
20594
        # verify data
20595
        data = tifs.asarray(out='memmap')
20596
        assert data.flags['C_CONTIGUOUS']
20597
        assert data.shape == (2, 378, 256, 256)
20598
        assert data.dtype == numpy.dtype('<u2')
20599
        assert data[1, 377, 70, 146] == 29
20600
        del data
20601

20602

20603
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_LARGE, reason=REASON)
20604
def test_dependent_tiffslide():
20605
    """Test tiffslide package."""
20606
    # https://github.com/bayer-science-for-a-better-life/tiffslide
20607
    try:
20608
        from tiffslide import TiffSlide
20609
    except ImportError:
20610
        pytest.skip('tiffslide missing')
20611

20612
    fname = private_file('AperioSVS/CMU-1.svs')
20613

20614
    with TiffSlide(fname) as slide:
20615
        region = slide.read_region((300, 400), 0, (512, 512), as_array=True)
20616
        assert tuple(region[150, 200]) == (243, 246, 246)
20617
        slide.get_thumbnail((200, 200))
20618

20619

20620
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_LARGE or not IS_WIN, reason=REASON)
20621
def test_dependent_opentile():
20622
    """Test opentile package."""
20623
    # https://github.com/imi-bigpicture/opentile
20624
    try:
20625
        from hashlib import md5
20626

20627
        import turbojpeg
20628
        from opentile.formats import NdpiTiler
20629
        from opentile.geometry import Point
20630
    except ImportError:
20631
        pytest.skip('opentile missing')
20632

20633
    fname = private_file('HamamatsuNDPI/CMU-1.ndpi')
20634

20635
    turbo_path = os.path.join(
20636
        os.path.dirname(turbojpeg.__file__), 'turbojpeg.dll'
20637
    )
20638

20639
    with NdpiTiler(
20640
        fname,
20641
        512,
20642
        turbo_path=turbo_path,
20643
    ) as tiler:
20644
        # from example
20645
        tile = tiler.get_tile(0, 0, 0, (0, 0))
20646
        assert md5(tile).hexdigest() in (
20647
            '30c69cab610e5b3db4beac63806d6513',
20648
            'e813041cd57d1d078cf1564c0ed9ad7f',
20649
        )
20650
        # read from file handle
20651
        level = tiler.get_level(0)
20652
        offset = level._page.dataoffsets[50]
20653
        length = level._page.databytecounts[50]
20654
        fh = level._page.parent.filehandle
20655
        fh.seek(offset)
20656
        data = fh.read(length)
20657
        assert length == 700
20658
        assert offset == 33451
20659
        assert md5(data).hexdigest() == '2a903c6e05bd10f10d856eecceb591f0'
20660
        # read level
20661
        data = level._read_frame(50)
20662
        assert md5(data).hexdigest() == '2a903c6e05bd10f10d856eecceb591f0'
20663
        # read frame
20664
        index = level._get_stripe_position_to_index(Point(50, 0))
20665
        stripe = level._read_frame(index)
20666
        assert md5(stripe).hexdigest() == '2a903c6e05bd10f10d856eecceb591f0'
20667
        # get frame
20668
        image = level._read_extended_frame(Point(10, 10), level.frame_size)
20669
        assert md5(image).hexdigest() == 'aeffd12997ca6c232d0ef35aaa35f6b7'
20670
        # get tile
20671
        tile = level.get_tile((0, 0))
20672
        assert md5(tile).hexdigest() in (
20673
            '30c69cab610e5b3db4beac63806d6513',
20674
            'e813041cd57d1d078cf1564c0ed9ad7f',
20675
        )
20676
        tile = level.get_tile((20, 20))
20677
        assert md5(tile).hexdigest() in (
20678
            'fec8116d05485df513f4f41e13eaa994',
20679
            'e755ee12d9fd65fc601e70951ce90696',
20680
        )
20681

20682

20683
@pytest.mark.skipif(SKIP_PUBLIC or SKIP_DASK, reason=REASON)
20684
def test_dependent_aicsimageio():
20685
    """Test aicsimageio package."""
20686
    # https://github.com/AllenCellModeling/aicsimageio
20687
    try:
20688
        import aicsimageio
20689
    except ImportError:
20690
        pytest.skip('aicsimageio or dependencies missing')
20691

20692
    fname = public_file('tifffile/multiscene_pyramidal.ome.tif')
20693

20694
    img = aicsimageio.AICSImage(fname)
20695
    assert img.shape == (16, 2, 32, 256, 256)
20696
    assert img.dims.order == 'TCZYX'
20697
    assert img.dims.X == 256
20698
    assert img.data.shape == (16, 2, 32, 256, 256)
20699
    assert img.xarray_data.dims == ('T', 'C', 'Z', 'Y', 'X')
20700
    t1 = img.get_image_data('ZCYX', T=1)
20701
    assert t1.shape == (32, 2, 256, 256)
20702
    assert img.current_scene == 'Image:0'
20703
    assert img.scenes == ('Image:0', 'Image:1')
20704
    img.set_scene(1)
20705
    assert img.current_scene == 'Image:1'
20706
    assert img.shape == (1, 1, 1, 128, 128, 3)
20707
    img.set_scene('Image:0')
20708
    lazy_t1 = img.get_image_dask_data('ZCYX', T=1)
20709
    assert_array_equal(lazy_t1.compute(), t1)
20710

20711

20712
@pytest.mark.xfail(reason=REASON)
20713
@pytest.mark.skipif(SKIP_PUBLIC, reason=REASON)
20714
def test_dependent_imageio():
20715
    """Test imageio package."""
20716
    # https://github.com/imageio/imageio/blob/master/tests/test_tifffile.py
20717
    # TODO: use imageio.v3
20718
    try:
20719
        import imageio.v2 as iio
20720
    except ImportError:
20721
        pytest.skip('imageio missing')
20722

20723
    data = numpy.ones((10, 10, 3), numpy.uint8) * 2
20724
    filename2 = public_file('imageio/multipage_rgb.tif')
20725
    filename3 = public_file('imageio/test_tiff2.tiff')
20726

20727
    with TempFileName('depend_imageio') as fname1:
20728
        # one image
20729
        iio.imwrite(fname1, data)
20730
        im = iio.imread(fname1)
20731
        ims = iio.mimread(fname1)
20732
        assert im.shape == data.shape
20733
        assert_array_equal(im, data)
20734
        assert len(ims) == 1
20735

20736
        # multiple images
20737
        iio.mimwrite(fname1, [data, data, data])
20738
        im = iio.imread(fname1)
20739
        ims = iio.mimread(fname1)
20740
        assert im.shape == data.shape
20741
        assert_array_equal(im, data)
20742
        assert len(ims) == 3
20743
        for i in range(3):
20744
            assert ims[i].shape == data.shape
20745
            assert_array_equal(ims[i], data)
20746

20747
        # volumetric data
20748
        iio.volwrite(fname1, numpy.tile(data, (3, 1, 1, 1)))
20749
        vol = iio.volread(fname1)
20750
        vols = iio.mvolread(fname1)
20751
        assert vol.shape == (3,) + data.shape
20752
        assert len(vols) == 1 and vol.shape == vols[0].shape
20753
        for i in range(3):
20754
            assert_array_equal(vol[i], data)
20755

20756
        # remote channel-first volume rgb (2, 3, 10, 10)
20757

20758
        img = iio.mimread(filename2)
20759
        assert len(img) == 2
20760
        assert img[0].shape == (3, 10, 10)
20761

20762
        # mixed
20763
        W = iio.save(fname1)
20764
        W.set_meta_data({'planarconfig': 'SEPARATE'})
20765
        assert W.format.name == 'TIFF'
20766
        W.append_data(data)
20767
        W.append_data(data)
20768
        W.close()
20769
        #
20770
        R = iio.read(fname1)
20771
        assert R.format.name == 'TIFF'
20772
        ims = list(R)  # == [im for im in R]
20773
        assert_array_equal(ims[0], data)
20774
        # fail
20775
        with pytest.raises(IndexError):
20776
            R.get_data(-1)
20777

20778
        with pytest.raises(IndexError):
20779
            R.get_data(3)
20780

20781
        # ensure imread + imwrite works round trip
20782
        im1 = iio.imread(fname1)
20783
        iio.imwrite(filename3, im1)
20784
        im3 = iio.imread(filename3)
20785
        assert im1.ndim == 3
20786
        assert im1.shape == im3.shape
20787
        assert_array_equal(im1, im3)
20788

20789
        # ensure imread + imwrite works round trip - volume like
20790
        im1 = numpy.stack(iio.mimread(fname1))
20791
        iio.volwrite(filename3, im1)
20792
        im3 = iio.volread(filename3)
20793
        assert im1.ndim == 4
20794
        assert im1.shape == im3.shape
20795
        assert_array_equal(im1, im3)
20796

20797
        # read metadata
20798
        md = iio.get_reader(filename2).get_meta_data()
20799
        assert not md['is_imagej']
20800
        assert md['description'] == 'shape=(2,3,10,10)'
20801
        assert md['description1'] == ""
20802
        assert md['datetime'] == datetime.datetime(2015, 5, 9, 9, 8, 29)
20803
        assert md['software'] == 'tifffile.py'
20804

20805
        # write metadata
20806
        dt = datetime.datetime(2018, 8, 6, 15, 35, 5)
20807
        with iio.get_writer(fname1, software='testsoftware') as w:
20808
            w.append_data(
20809
                numpy.zeros((10, 10)),
20810
                meta={'description': 'test desc', 'datetime': dt},
20811
            )
20812
            w.append_data(
20813
                numpy.zeros((10, 10)), meta={'description': 'another desc'}
20814
            )
20815
        with iio.get_reader(fname1) as r:
20816
            for md in r.get_meta_data(), r.get_meta_data(0):
20817
                assert 'datetime' in md
20818
                assert md['datetime'] == dt
20819
                assert 'software' in md
20820
                assert md['software'] == 'testsoftware'
20821
                assert 'description' in md
20822
                assert md['description'] == 'test desc'
20823

20824
            md = r.get_meta_data(1)
20825
            assert 'description' in md
20826
            assert md['description'] == 'another desc'
20827

20828

20829
@pytest.mark.skipif(SKIP_PRIVATE, reason=REASON)
20830
def test_dependent_pims():
20831
    """Test PIMS package."""
20832
    # https://github.com/soft-matter/pims
20833
    try:
20834
        from pims import TiffStack_tifffile
20835
    except ImportError:
20836
        pytest.skip('pims or dependencies missing')
20837

20838
    fname = private_file('pims/tiff_stack.tif')
20839

20840
    ims = TiffStack_tifffile(fname)
20841
    assert_array_equal(ims.get_frame(2), imread(fname, key=2))
20842
    repr(ims)
20843
    ims.close()
20844

20845

20846
@pytest.mark.skipif(SKIP_PRIVATE or SKIP_ZARR, reason=REASON)
20847
def test_dependent_kerchunk():
20848
    """Test kerchunk package."""
20849
    # https://github.com/fsspec/kerchunk/blob/main/kerchunk/tests/test_tiff.py
20850
    try:
20851
        import kerchunk.tiff
20852
    except ImportError:
20853
        pytest.skip('kerchunk or dependencies missing')
20854

20855
    fname = private_file('kerchunk/lcmap_tiny_cog_2019.tif')
20856
    fname = pathlib.Path(fname).as_uri()
20857

20858
    out = kerchunk.tiff.tiff_to_zarr(fname)
20859
    m = fsspec.get_mapper('reference://', fo=out)
20860
    z = zarr.open(m)
20861
    assert list(z) == ['0', '1', '2']
20862
    assert z.attrs['multiscales'] == [
20863
        {
20864
            'datasets': [{'path': '0'}, {'path': '1'}, {'path': '2'}],
20865
            'metadata': {},
20866
            'name': '',
20867
            'version': '0.1',
20868
        }
20869
    ]
20870
    assert z['0'].shape == (2048, 2048)
20871
    assert z['0'][:].max() == 8
20872

20873
    fname = private_file('kerchunk/example.tif')
20874
    fname = pathlib.Path(fname).as_uri()
20875

20876
    out = kerchunk.tiff.tiff_to_zarr(fname)
20877
    m = fsspec.get_mapper('reference://', fo=out)
20878
    z = zarr.open(m)
20879

20880

20881
###############################################################################
20882

20883
if __name__ == '__main__':
20884
    import warnings
20885

20886
    # warnings.simplefilter('always')
20887
    warnings.filterwarnings('ignore', category=ImportWarning)
20888
    argv = sys.argv
20889
    argv.append('--cov-report=html')
20890
    argv.append('--cov=tifffile')
20891
    argv.append('--verbose')
20892
    sys.exit(pytest.main(argv))
20893

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.