Read and write TIFF files
=========================
Tifffile is a Python library to
(1) store NumPy arrays in TIFF (Tagged Image File Format) files, and
(2) read image and metadata from TIFF-like files used in bioimaging.
Image and metadata can be read from TIFF, BigTIFF, OME-TIFF, GeoTIFF,
Adobe DNG, ZIF (Zoomable Image File Format), MetaMorph STK, Zeiss LSM,
ImageJ hyperstack, Micro-Manager MMStack and NDTiff, SGI, NIHImage,
Olympus FluoView and SIS, ScanImage, Molecular Dynamics GEL,
Aperio SVS, Leica SCN, Roche BIF, PerkinElmer QPTIFF (QPI, PKI),
Hamamatsu NDPI, Argos AVS, and Philips DP formatted files.
Image data can be read as NumPy arrays or Zarr arrays/groups from strips,
tiles, pages (IFDs), SubIFDs, higher order series, and pyramidal levels.
Image data can be written to TIFF, BigTIFF, OME-TIFF, and ImageJ hyperstack
compatible files in multi-page, volumetric, pyramidal, memory-mappable,
tiled, predicted, or compressed form.
Many compression and predictor schemes are supported via the imagecodecs
library, including LZW, PackBits, Deflate, PIXTIFF, LZMA, LERC, Zstd,
JPEG (8 and 12-bit, lossless), JPEG 2000, JPEG XR, JPEG XL, WebP, PNG, EER,
Jetraw, 24-bit floating-point, and horizontal differencing.
Tifffile can also be used to inspect TIFF structures, read image data from
multi-dimensional file sequences, write fsspec ReferenceFileSystem for
TIFF files and image file sequences, patch TIFF tag values, and parse
many proprietary metadata formats.
:Author: `Christoph Gohlke <https://www.cgohlke.com>`_
:License: BSD 3-Clause
:Version: 2024.12.12
:DOI: `10.5281/zenodo.6795860 <https://doi.org/10.5281/zenodo.6795860>`_
Quickstart
----------
Install the tifffile package and all dependencies from the
`Python Package Index <https://pypi.org/project/tifffile/>`_::
python -m pip install -U tifffile[all]
Tifffile is also available in other package repositories such as Anaconda,
Debian, and MSYS2.
The tifffile library is type annotated and documented via docstrings::
python -c "import tifffile; help(tifffile)"
Tifffile can be used as a console script to inspect and preview TIFF files::
python -m tifffile --help
See `Examples`_ for using the programming interface.
Source code and support are available on
`GitHub <https://github.com/cgohlke/tifffile>`_.
Support is also provided on the
`image.sc <https://forum.image.sc/tag/tifffile>`_ forum.
Requirements
------------
This revision was tested with the following requirements and dependencies
(other versions may work):
- `CPython <https://www.python.org>`_ 3.10.11, 3.11.9, 3.12.8, 3.13.1 64-bit
- `NumPy <https://pypi.org/project/numpy/>`_ 2.1.3
- `Imagecodecs <https://pypi.org/project/imagecodecs/>`_ 2024.9.22
(required for encoding or decoding LZW, JPEG, etc. compressed segments)
- `Matplotlib <https://pypi.org/project/matplotlib/>`_ 3.9.3
(required for plotting)
- `Lxml <https://pypi.org/project/lxml/>`_ 5.3.0
(required only for validating and printing XML)
- `Zarr <https://pypi.org/project/zarr/>`_ 2.18.4
(required only for opening Zarr stores; Zarr 3 is not compatible)
- `Fsspec <https://pypi.org/project/fsspec/>`_ 2024.10.0
(required only for opening ReferenceFileSystem files)
Revisions
---------
2024.12.12
- Pass 5110 tests.
- Read PlaneProperty from STK UIC1Tag (#280).
- Allow 'None' as alias for COMPRESSION.NONE and PREDICTOR.NONE (#274).
- Zarr 3 is not supported (#272).
2024.9.20
- Fix writing colormap to ImageJ files (breaking).
- Improve typing.
- Remove support for Python 3.9.
2024.8.30
- Support writing OME Dataset and some StructuredAnnotations elements.
2024.8.28
- Fix LSM scan types and dimension orders (#269, breaking).
- Use IO[bytes] instead of BinaryIO for typing (#268).
2024.8.24
- Do not remove trailing length-1 dimension writing non-shaped file (breaking).
- Fix writing OME-TIFF with certain modulo axes orders.
- Make imshow NaN aware.
2024.8.10
- Relax bitspersample check for JPEG, JPEG2K, and JPEGXL compression (#265).
2024.7.24
- Fix reading contiguous multi-page series via Zarr store (#67).
2024.7.21
- Fix integer overflow in product function caused by numpy types.
- Allow tag reader functions to fail.
2024.7.2
- Enable memmap to create empty files with non-native byte order.
- Deprecate Python 3.9, support Python 3.13.
2024.6.18
- Ensure TiffPage.nodata is castable to dtype (breaking, #260).
- Support Argos AVS slides.
2024.5.22
- Derive TiffPages, TiffPageSeries, FileSequence, StoredShape from Sequence.
- Truncate circular IFD chain, do not raise TiffFileError (breaking).
- Deprecate access to TiffPages.pages and FileSequence.files.
- Enable DeprecationWarning for enums in TIFF namespace.
- Remove some deprecated code (breaking).
- Add iccprofile property to TiffPage and parameter to TiffWriter.write.
- Do not detect VSI as SIS format.
- Limit length of logged exception messages.
- Fix docstring examples not correctly rendered on GitHub (#254, #255).
2024.5.10
- Support reading JPEGXL compression in DNG 1.7.
- Read invalid TIFF created by IDEAS software.
2024.5.3
- Fix reading incompletely written LSM.
- Fix reading Philips DP with extra rows of tiles (#253, breaking).
2024.4.24
- Fix compatibility issue with numpy 2 (#252).
2024.4.18
- Fix write_fsspec when last row of tiles is missing in Philips slide (#249).
- Add option not to quote file names in write_fsspec.
- Allow compress bilevel images with deflate, LZMA, and Zstd.
2024.2.12
- Deprecate dtype, add chunkdtype parameter in FileSequence.asarray.
- Add imreadargs parameters passed to FileSequence.imread.
2024.1.30
- Fix compatibility issue with numpy 2 (#238).
- Enable DeprecationWarning for tuple compression argument.
- Parse sequence of numbers in xml2dict.
2023.12.9
- …
Refer to the CHANGES file for older revisions.
Notes
-----
TIFF, the Tagged Image File Format, was created by the Aldus Corporation and
Adobe Systems Incorporated.
Tifffile supports a subset of the TIFF6 specification, mainly 8, 16, 32, and
64-bit integer, 16, 32 and 64-bit float, grayscale and multi-sample images.
Specifically, CCITT and OJPEG compression, chroma subsampling without JPEG
compression, color space transformations, samples with differing types, or
IPTC, ICC, and XMP metadata are not implemented.
Besides classic TIFF, tifffile supports several TIFF-like formats that do not
strictly adhere to the TIFF6 specification. Some formats allow file and data
sizes to exceed the 4 GB limit of the classic TIFF:
- **BigTIFF** is identified by version number 43 and uses different file
header, IFD, and tag structures with 64-bit offsets. The format also adds
64-bit data types. Tifffile can read and write BigTIFF files.
- **ImageJ hyperstacks** store all image data, which may exceed 4 GB,
contiguously after the first IFD. Files > 4 GB contain one IFD only.
The size and shape of the up to 6-dimensional image data can be determined
from the ImageDescription tag of the first IFD, which is Latin-1 encoded.
Tifffile can read and write ImageJ hyperstacks.
- **OME-TIFF** files store up to 8-dimensional image data in one or multiple
TIFF or BigTIFF files. The UTF-8 encoded OME-XML metadata found in the
ImageDescription tag of the first IFD defines the position of TIFF IFDs in
the high dimensional image data. Tifffile can read OME-TIFF files (except
multi-file pyramidal) and write NumPy arrays to single-file OME-TIFF.
- **Micro-Manager NDTiff** stores multi-dimensional image data in one
or more classic TIFF files. Metadata contained in a separate NDTiff.index
binary file defines the position of the TIFF IFDs in the image array.
Each TIFF file also contains metadata in a non-TIFF binary structure at
offset 8. Downsampled image data of pyramidal datasets are stored in
separate folders. Tifffile can read NDTiff files. Version 0 and 1 series,
tiling, stitching, and multi-resolution pyramids are not supported.
- **Micro-Manager MMStack** stores 6-dimensional image data in one or more
classic TIFF files. Metadata contained in non-TIFF binary structures and
JSON strings define the image stack dimensions and the position of the image
frame data in the file and the image stack. The TIFF structures and metadata
are often corrupted or wrong. Tifffile can read MMStack files.
- **Carl Zeiss LSM** files store all IFDs below 4 GB and wrap around 32-bit
StripOffsets pointing to image data above 4 GB. The StripOffsets of each
series and position require separate unwrapping. The StripByteCounts tag
contains the number of bytes for the uncompressed data. Tifffile can read
LSM files of any size.
- **MetaMorph Stack, STK** files contain additional image planes stored
contiguously after the image data of the first page. The total number of
planes is equal to the count of the UIC2tag. Tifffile can read STK files.
- **ZIF**, the Zoomable Image File format, is a subspecification of BigTIFF
with SGI's ImageDepth extension and additional compression schemes.
Only little-endian, tiled, interleaved, 8-bit per sample images with
JPEG, PNG, JPEG XR, and JPEG 2000 compression are allowed. Tifffile can
read and write ZIF files.
- **Hamamatsu NDPI** files use some 64-bit offsets in the file header, IFD,
and tag structures. Single, LONG typed tag values can exceed 32-bit.
The high bytes of 64-bit tag values and offsets are stored after IFD
structures. Tifffile can read NDPI files > 4 GB.
JPEG compressed segments with dimensions >65530 or missing restart markers
cannot be decoded with common JPEG libraries. Tifffile works around this
limitation by separately decoding the MCUs between restart markers, which
performs poorly. BitsPerSample, SamplesPerPixel, and
PhotometricInterpretation tags may contain wrong values, which can be
corrected using the value of tag 65441.
- **Philips TIFF** slides store padded ImageWidth and ImageLength tag values
for tiled pages. The values can be corrected using the DICOM_PIXEL_SPACING
attributes of the XML formatted description of the first page. Tile offsets
and byte counts may be 0. Tifffile can read Philips slides.
- **Ventana/Roche BIF** slides store tiles and metadata in a BigTIFF container.
Tiles may overlap and require stitching based on the TileJointInfo elements
in the XMP tag. Volumetric scans are stored using the ImageDepth extension.
Tifffile can read BIF and decode individual tiles but does not perform
stitching.
- **ScanImage** optionally allows corrupted non-BigTIFF files > 2 GB.
The values of StripOffsets and StripByteCounts can be recovered using the
constant differences of the offsets of IFD and tag values throughout the
file. Tifffile can read such files if the image data are stored contiguously
in each page.
- **GeoTIFF sparse** files allow strip or tile offsets and byte counts to be 0.
Such segments are implicitly set to 0 or the NODATA value on reading.
Tifffile can read GeoTIFF sparse files.
- **Tifffile shaped** files store the array shape and user-provided metadata
of multi-dimensional image series in JSON format in the ImageDescription tag
of the first page of the series. The format allows for multiple series,
SubIFDs, sparse segments with zero offset and byte count, and truncated
series, where only the first page of a series is present, and the image data
are stored contiguously. No other software besides Tifffile supports the
truncated format.
Other libraries for reading, writing, inspecting, or manipulating scientific
TIFF files from Python are
`aicsimageio <https://pypi.org/project/aicsimageio>`_,
`apeer-ometiff-library
<https://github.com/apeer-micro/apeer-ometiff-library>`_,
`bigtiff <https://pypi.org/project/bigtiff>`_,
`fabio.TiffIO <https://github.com/silx-kit/fabio>`_,
`GDAL <https://github.com/OSGeo/gdal/>`_,
`imread <https://github.com/luispedro/imread>`_,
`large_image <https://github.com/girder/large_image>`_,
`openslide-python <https://github.com/openslide/openslide-python>`_,
`opentile <https://github.com/imi-bigpicture/opentile>`_,
`pylibtiff <https://github.com/pearu/pylibtiff>`_,
`pylsm <https://launchpad.net/pylsm>`_,
`pymimage <https://github.com/ardoi/pymimage>`_,
`python-bioformats <https://github.com/CellProfiler/python-bioformats>`_,
`pytiff <https://github.com/FZJ-INM1-BDA/pytiff>`_,
`scanimagetiffreader-python
<https://gitlab.com/vidriotech/scanimagetiffreader-python>`_,
`SimpleITK <https://github.com/SimpleITK/SimpleITK>`_,
`slideio <https://gitlab.com/bioslide/slideio>`_,
`tiffslide <https://github.com/bayer-science-for-a-better-life/tiffslide>`_,
`tifftools <https://github.com/DigitalSlideArchive/tifftools>`_,
`tyf <https://github.com/Moustikitos/tyf>`_,
`xtiff <https://github.com/BodenmillerGroup/xtiff>`_, and
`ndtiff <https://github.com/micro-manager/NDTiffStorage>`_.
References
----------
- TIFF 6.0 Specification and Supplements. Adobe Systems Incorporated.
https://www.adobe.io/open/standards/TIFF.html
- TIFF File Format FAQ. https://www.awaresystems.be/imaging/tiff/faq.html
- The BigTIFF File Format.
https://www.awaresystems.be/imaging/tiff/bigtiff.html
- MetaMorph Stack (STK) Image File Format.
http://mdc.custhelp.com/app/answers/detail/a_id/18862
- Image File Format Description LSM 5/7 Release 6.0 (ZEN 2010).
Carl Zeiss MicroImaging GmbH. BioSciences. May 10, 2011
- The OME-TIFF format.
https://docs.openmicroscopy.org/ome-model/latest/
- UltraQuant(r) Version 6.0 for Windows Start-Up Guide.
http://www.ultralum.com/images%20ultralum/pdf/UQStart%20Up%20Guide.pdf
- Micro-Manager File Formats.
https://micro-manager.org/wiki/Micro-Manager_File_Formats
- ScanImage BigTiff Specification.
https://docs.scanimage.org/Appendix/ScanImage+BigTiff+Specification.html
- ZIF, the Zoomable Image File format. https://zif.photo/
- GeoTIFF File Format https://gdal.org/drivers/raster/gtiff.html
- Cloud optimized GeoTIFF.
https://github.com/cogeotiff/cog-spec/blob/master/spec.md
- Tags for TIFF and Related Specifications. Digital Preservation.
https://www.loc.gov/preservation/digital/formats/content/tiff_tags.shtml
- CIPA DC-008-2016: Exchangeable image file format for digital still cameras:
Exif Version 2.31.
http://www.cipa.jp/std/documents/e/DC-008-Translation-2016-E.pdf
- The EER (Electron Event Representation) file format.
https://github.com/fei-company/EerReaderLib
- Digital Negative (DNG) Specification. Version 1.7.1.0, September 2023.
https://helpx.adobe.com/content/dam/help/en/photoshop/pdf/DNG_Spec_1_7_1_0.pdf
- Roche Digital Pathology. BIF image file format for digital pathology.
https://diagnostics.roche.com/content/dam/diagnostics/Blueprint/en/pdf/rmd/Roche-Digital-Pathology-BIF-Whitepaper.pdf
- Astro-TIFF specification. https://astro-tiff.sourceforge.io/
- Aperio Technologies, Inc. Digital Slides and Third-Party Data Interchange.
Aperio_Digital_Slides_and_Third-party_data_interchange.pdf
- PerkinElmer image format.
https://downloads.openmicroscopy.org/images/Vectra-QPTIFF/perkinelmer/PKI_Image%20Format.docx
- NDTiffStorage. https://github.com/micro-manager/NDTiffStorage
- Argos AVS File Format.
https://github.com/user-attachments/files/15580286/ARGOS.AVS.File.Format.pdf
Examples
--------
Write a NumPy array to a single-page RGB TIFF file:
>>> data = numpy.random.randint(0, 255, (256, 256, 3), 'uint8')
>>> imwrite('temp.tif', data, photometric='rgb')
Read the image from the TIFF file as NumPy array:
>>> image = imread('temp.tif')
>>> image.shape
(256, 256, 3)
Use the `photometric` and `planarconfig` arguments to write a 3x3x3 NumPy
array to an interleaved RGB, a planar RGB, or a 3-page grayscale TIFF:
>>> data = numpy.random.randint(0, 255, (3, 3, 3), 'uint8')
>>> imwrite('temp.tif', data, photometric='rgb')
>>> imwrite('temp.tif', data, photometric='rgb', planarconfig='separate')
>>> imwrite('temp.tif', data, photometric='minisblack')
Use the `extrasamples` argument to specify how extra components are
interpreted, for example, for an RGBA image with unassociated alpha channel:
>>> data = numpy.random.randint(0, 255, (256, 256, 4), 'uint8')
>>> imwrite('temp.tif', data, photometric='rgb', extrasamples=['unassalpha'])
Write a 3-dimensional NumPy array to a multi-page, 16-bit grayscale TIFF file:
>>> data = numpy.random.randint(0, 2**12, (64, 301, 219), 'uint16')
>>> imwrite('temp.tif', data, photometric='minisblack')
Read the whole image stack from the multi-page TIFF file as NumPy array:
>>> image_stack = imread('temp.tif')
>>> image_stack.shape
(64, 301, 219)
>>> image_stack.dtype
dtype('uint16')
Read the image from the first page in the TIFF file as NumPy array:
>>> image = imread('temp.tif', key=0)
>>> image.shape
(301, 219)
Read images from a selected range of pages:
>>> images = imread('temp.tif', key=range(4, 40, 2))
>>> images.shape
(18, 301, 219)
Iterate over all pages in the TIFF file and successively read images:
>>> with TiffFile('temp.tif') as tif:
... for page in tif.pages:
... image = page.asarray()
...
Get information about the image stack in the TIFF file without reading
any image data:
>>> tif = TiffFile('temp.tif')
>>> len(tif.pages) # number of pages in the file
64
>>> page = tif.pages[0] # get shape and dtype of image in first page
>>> page.shape
(301, 219)
>>> page.dtype
dtype('uint16')
>>> page.axes
'YX'
>>> series = tif.series[0] # get shape and dtype of first image series
>>> series.shape
(64, 301, 219)
>>> series.dtype
dtype('uint16')
>>> series.axes
'QYX'
>>> tif.close()
Inspect the "XResolution" tag from the first page in the TIFF file:
>>> with TiffFile('temp.tif') as tif:
... tag = tif.pages[0].tags['XResolution']
...
>>> tag.value
(1, 1)
>>> tag.name
'XResolution'
>>> tag.code
282
>>> tag.count
1
>>> tag.dtype
<DATATYPE.RATIONAL: 5>
Iterate over all tags in the TIFF file:
>>> with TiffFile('temp.tif') as tif:
... for page in tif.pages:
... for tag in page.tags:
... tag_name, tag_value = tag.name, tag.value
...
Overwrite the value of an existing tag, for example, XResolution:
>>> with TiffFile('temp.tif', mode='r+') as tif:
... _ = tif.pages[0].tags['XResolution'].overwrite((96000, 1000))
...
Write a 5-dimensional floating-point array using BigTIFF format, separate
color components, tiling, Zlib compression level 8, horizontal differencing
predictor, and additional metadata:
>>> data = numpy.random.rand(2, 5, 3, 301, 219).astype('float32')
>>> imwrite(
... 'temp.tif',
... data,
... bigtiff=True,
... photometric='rgb',
... planarconfig='separate',
... tile=(32, 32),
... compression='zlib',
... compressionargs={'level': 8},
... predictor=True,
... metadata={'axes': 'TZCYX'},
... )
Write a 10 fps time series of volumes with xyz voxel size 2.6755x2.6755x3.9474
micron^3 to an ImageJ hyperstack formatted TIFF file:
>>> volume = numpy.random.randn(6, 57, 256, 256).astype('float32')
>>> image_labels = [f'{i}' for i in range(volume.shape[0] * volume.shape[1])]
>>> imwrite(
... 'temp.tif',
... volume,
... imagej=True,
... resolution=(1.0 / 2.6755, 1.0 / 2.6755),
... metadata={
... 'spacing': 3.947368,
... 'unit': 'um',
... 'finterval': 1 / 10,
... 'fps': 10.0,
... 'axes': 'TZYX',
... 'Labels': image_labels,
... },
... )
Read the volume and metadata from the ImageJ hyperstack file:
>>> with TiffFile('temp.tif') as tif:
... volume = tif.asarray()
... axes = tif.series[0].axes
... imagej_metadata = tif.imagej_metadata
...
>>> volume.shape
(6, 57, 256, 256)
>>> axes
'TZYX'
>>> imagej_metadata['slices']
57
>>> imagej_metadata['frames']
6
Memory-map the contiguous image data in the ImageJ hyperstack file:
>>> memmap_volume = memmap('temp.tif')
>>> memmap_volume.shape
(6, 57, 256, 256)
>>> del memmap_volume
Create a TIFF file containing an empty image and write to the memory-mapped
NumPy array (note: this does not work with compression or tiling):
>>> memmap_image = memmap(
... 'temp.tif', shape=(256, 256, 3), dtype='float32', photometric='rgb'
... )
>>> type(memmap_image)
<class 'numpy.memmap'>
>>> memmap_image[255, 255, 1] = 1.0
>>> memmap_image.flush()
>>> del memmap_image
Write two NumPy arrays to a multi-series TIFF file (note: other TIFF readers
will not recognize the two series; use the OME-TIFF format for better
interoperability):
>>> series0 = numpy.random.randint(0, 255, (32, 32, 3), 'uint8')
>>> series1 = numpy.random.randint(0, 255, (4, 256, 256), 'uint16')
>>> with TiffWriter('temp.tif') as tif:
... tif.write(series0, photometric='rgb')
... tif.write(series1, photometric='minisblack')
...
Read the second image series from the TIFF file:
>>> series1 = imread('temp.tif', series=1)
>>> series1.shape
(4, 256, 256)
Successively write the frames of one contiguous series to a TIFF file:
>>> data = numpy.random.randint(0, 255, (30, 301, 219), 'uint8')
>>> with TiffWriter('temp.tif') as tif:
... for frame in data:
... tif.write(frame, contiguous=True)
...
Append an image series to the existing TIFF file (note: this does not work
with ImageJ hyperstack or OME-TIFF files):
>>> data = numpy.random.randint(0, 255, (301, 219, 3), 'uint8')
>>> imwrite('temp.tif', data, photometric='rgb', append=True)
Create a TIFF file from a generator of tiles:
>>> data = numpy.random.randint(0, 2**12, (31, 33, 3), 'uint16')
>>> def tiles(data, tileshape):
... for y in range(0, data.shape[0], tileshape[0]):
... for x in range(0, data.shape[1], tileshape[1]):
... yield data[y : y + tileshape[0], x : x + tileshape[1]]
...
>>> imwrite(
... 'temp.tif',
... tiles(data, (16, 16)),
... tile=(16, 16),
... shape=data.shape,
... dtype=data.dtype,
... photometric='rgb',
... )
Write a multi-dimensional, multi-resolution (pyramidal), multi-series OME-TIFF
file with optional metadata. Sub-resolution images are written to SubIFDs.
Limit parallel encoding to 2 threads. Write a thumbnail image as a separate
image series:
>>> data = numpy.random.randint(0, 255, (8, 2, 512, 512, 3), 'uint8')
>>> subresolutions = 2
>>> pixelsize = 0.29 # micrometer
>>> with TiffWriter('temp.ome.tif', bigtiff=True) as tif:
... metadata = {
... 'axes': 'TCYXS',
... 'SignificantBits': 8,
... 'TimeIncrement': 0.1,
... 'TimeIncrementUnit': 's',
... 'PhysicalSizeX': pixelsize,
... 'PhysicalSizeXUnit': 'µm',
... 'PhysicalSizeY': pixelsize,
... 'PhysicalSizeYUnit': 'µm',
... 'Channel': {'Name': ['Channel 1', 'Channel 2']},
... 'Plane': {'PositionX': [0.0] * 16, 'PositionXUnit': ['µm'] * 16},
... 'Description': 'A multi-dimensional, multi-resolution image',
... 'MapAnnotation': { # for OMERO
... 'Namespace': 'openmicroscopy.org/PyramidResolution',
... '1': '256 256',
... '2': '128 128',
... },
... }
... options = dict(
... photometric='rgb',
... tile=(128, 128),
... compression='jpeg',
... resolutionunit='CENTIMETER',
... maxworkers=2,
... )
... tif.write(
... data,
... subifds=subresolutions,
... resolution=(1e4 / pixelsize, 1e4 / pixelsize),
... metadata=metadata,
... **options,
... )
... # write pyramid levels to the two subifds
... # in production use resampling to generate sub-resolution images
... for level in range(subresolutions):
... mag = 2 ** (level + 1)
... tif.write(
... data[..., ::mag, ::mag, :],
... subfiletype=1,
... resolution=(1e4 / mag / pixelsize, 1e4 / mag / pixelsize),
... **options,
... )
... # add a thumbnail image as a separate series
... # it is recognized by QuPath as an associated image
... thumbnail = (data[0, 0, ::8, ::8] >> 2).astype('uint8')
... tif.write(thumbnail, metadata={'Name': 'thumbnail'})
...
Access the image levels in the pyramidal OME-TIFF file:
>>> baseimage = imread('temp.ome.tif')
>>> second_level = imread('temp.ome.tif', series=0, level=1)
>>> with TiffFile('temp.ome.tif') as tif:
... baseimage = tif.series[0].asarray()
... second_level = tif.series[0].levels[1].asarray()
... number_levels = len(tif.series[0].levels) # includes base level
...
Iterate over and decode single JPEG compressed tiles in the TIFF file:
>>> with TiffFile('temp.ome.tif') as tif:
... fh = tif.filehandle
... for page in tif.pages:
... for index, (offset, bytecount) in enumerate(
... zip(page.dataoffsets, page.databytecounts)
... ):
... _ = fh.seek(offset)
... data = fh.read(bytecount)
... tile, indices, shape = page.decode(
... data, index, jpegtables=page.jpegtables
... )
...
Use Zarr 2 to read parts of the tiled, pyramidal images in the TIFF file:
>>> import zarr
>>> store = imread('temp.ome.tif', aszarr=True)
>>> z = zarr.open(store, mode='r')
>>> z
<zarr.hierarchy.Group '/' read-only>
>>> z[0] # base layer
<zarr.core.Array '/0' (8, 2, 512, 512, 3) uint8 read-only>
>>> z[0][2, 0, 128:384, 256:].shape # read a tile from the base layer
(256, 256, 3)
>>> store.close()
Load the base layer from the Zarr 2 store as a dask array:
>>> import dask.array
>>> store = imread('temp.ome.tif', aszarr=True)
>>> dask.array.from_zarr(store, 0)
dask.array<...shape=(8, 2, 512, 512, 3)...chunksize=(1, 1, 128, 128, 3)...
>>> store.close()
Write the Zarr 2 store to a fsspec ReferenceFileSystem in JSON format:
>>> store = imread('temp.ome.tif', aszarr=True)
>>> store.write_fsspec('temp.ome.tif.json', url='file://')
>>> store.close()
Open the fsspec ReferenceFileSystem as a Zarr group:
>>> import fsspec
>>> import imagecodecs.numcodecs
>>> imagecodecs.numcodecs.register_codecs()
>>> mapper = fsspec.get_mapper(
... 'reference://', fo='temp.ome.tif.json', target_protocol='file'
... )
>>> z = zarr.open(mapper, mode='r')
>>> z
<zarr.hierarchy.Group '/' read-only>
Create an OME-TIFF file containing an empty, tiled image series and write
to it via the Zarr interface (note: this does not work with compression):
>>> imwrite(
... 'temp2.ome.tif',
... shape=(8, 800, 600),
... dtype='uint16',
... photometric='minisblack',
... tile=(128, 128),
... metadata={'axes': 'CYX'},
... )
>>> store = imread('temp2.ome.tif', mode='r+', aszarr=True)
>>> z = zarr.open(store, mode='r+')
>>> z
<zarr.core.Array (8, 800, 600) uint16>
>>> z[3, 100:200, 200:300:2] = 1024
>>> store.close()
Read images from a sequence of TIFF files as NumPy array using two I/O worker
threads:
>>> imwrite('temp_C001T001.tif', numpy.random.rand(64, 64))
>>> imwrite('temp_C001T002.tif', numpy.random.rand(64, 64))
>>> image_sequence = imread(
... ['temp_C001T001.tif', 'temp_C001T002.tif'], ioworkers=2, maxworkers=1
... )
>>> image_sequence.shape
(2, 64, 64)
>>> image_sequence.dtype
dtype('float64')
Read an image stack from a series of TIFF files with a file name pattern
as NumPy or Zarr arrays:
>>> image_sequence = TiffSequence('temp_C0*.tif', pattern=r'_(C)(\d+)(T)(\d+)')
>>> image_sequence.shape
(1, 2)
>>> image_sequence.axes
'CT'
>>> data = image_sequence.asarray()
>>> data.shape
(1, 2, 64, 64)
>>> store = image_sequence.aszarr()
>>> zarr.open(store, mode='r')
<zarr.core.Array (1, 2, 64, 64) float64 read-only>
>>> image_sequence.close()
Write the Zarr 2 store to a fsspec ReferenceFileSystem in JSON format:
>>> store = image_sequence.aszarr()
>>> store.write_fsspec('temp.json', url='file://')
Open the fsspec ReferenceFileSystem as a Zarr array:
>>> import fsspec
>>> import tifffile.numcodecs
>>> tifffile.numcodecs.register_codec()
>>> mapper = fsspec.get_mapper(
... 'reference://', fo='temp.json', target_protocol='file'
... )
>>> zarr.open(mapper, mode='r')
<zarr.core.Array (1, 2, 64, 64) float64 read-only>
Inspect the TIFF file from the command line::
$ python -m tifffile temp.ome.tif
Raw data
{
"_id": null,
"home_page": "https://www.cgohlke.com",
"name": "tifffile",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.10",
"maintainer_email": null,
"keywords": null,
"author": "Christoph Gohlke",
"author_email": "cgohlke@cgohlke.com",
"download_url": "https://files.pythonhosted.org/packages/37/c9/fc4e490c5b0ccad68c98ea1d6e0f409bd7d50e2e8fc30a0725594d3104ff/tifffile-2024.12.12.tar.gz",
"platform": "any",
"description": "Read and write TIFF files\r\n=========================\r\n\r\nTifffile is a Python library to\r\n\r\n(1) store NumPy arrays in TIFF (Tagged Image File Format) files, and\r\n(2) read image and metadata from TIFF-like files used in bioimaging.\r\n\r\nImage and metadata can be read from TIFF, BigTIFF, OME-TIFF, GeoTIFF,\r\nAdobe DNG, ZIF (Zoomable Image File Format), MetaMorph STK, Zeiss LSM,\r\nImageJ hyperstack, Micro-Manager MMStack and NDTiff, SGI, NIHImage,\r\nOlympus FluoView and SIS, ScanImage, Molecular Dynamics GEL,\r\nAperio SVS, Leica SCN, Roche BIF, PerkinElmer QPTIFF (QPI, PKI),\r\nHamamatsu NDPI, Argos AVS, and Philips DP formatted files.\r\n\r\nImage data can be read as NumPy arrays or Zarr arrays/groups from strips,\r\ntiles, pages (IFDs), SubIFDs, higher order series, and pyramidal levels.\r\n\r\nImage data can be written to TIFF, BigTIFF, OME-TIFF, and ImageJ hyperstack\r\ncompatible files in multi-page, volumetric, pyramidal, memory-mappable,\r\ntiled, predicted, or compressed form.\r\n\r\nMany compression and predictor schemes are supported via the imagecodecs\r\nlibrary, including LZW, PackBits, Deflate, PIXTIFF, LZMA, LERC, Zstd,\r\nJPEG (8 and 12-bit, lossless), JPEG 2000, JPEG XR, JPEG XL, WebP, PNG, EER,\r\nJetraw, 24-bit floating-point, and horizontal differencing.\r\n\r\nTifffile can also be used to inspect TIFF structures, read image data from\r\nmulti-dimensional file sequences, write fsspec ReferenceFileSystem for\r\nTIFF files and image file sequences, patch TIFF tag values, and parse\r\nmany proprietary metadata formats.\r\n\r\n:Author: `Christoph Gohlke <https://www.cgohlke.com>`_\r\n:License: BSD 3-Clause\r\n:Version: 2024.12.12\r\n:DOI: `10.5281/zenodo.6795860 <https://doi.org/10.5281/zenodo.6795860>`_\r\n\r\nQuickstart\r\n----------\r\n\r\nInstall the tifffile package and all dependencies from the\r\n`Python Package Index <https://pypi.org/project/tifffile/>`_::\r\n\r\n python -m pip install -U tifffile[all]\r\n\r\nTifffile is also available in other package repositories such as Anaconda,\r\nDebian, and MSYS2.\r\n\r\nThe tifffile library is type annotated and documented via docstrings::\r\n\r\n python -c \"import tifffile; help(tifffile)\"\r\n\r\nTifffile can be used as a console script to inspect and preview TIFF files::\r\n\r\n python -m tifffile --help\r\n\r\nSee `Examples`_ for using the programming interface.\r\n\r\nSource code and support are available on\r\n`GitHub <https://github.com/cgohlke/tifffile>`_.\r\n\r\nSupport is also provided on the\r\n`image.sc <https://forum.image.sc/tag/tifffile>`_ forum.\r\n\r\nRequirements\r\n------------\r\n\r\nThis revision was tested with the following requirements and dependencies\r\n(other versions may work):\r\n\r\n- `CPython <https://www.python.org>`_ 3.10.11, 3.11.9, 3.12.8, 3.13.1 64-bit\r\n- `NumPy <https://pypi.org/project/numpy/>`_ 2.1.3\r\n- `Imagecodecs <https://pypi.org/project/imagecodecs/>`_ 2024.9.22\r\n (required for encoding or decoding LZW, JPEG, etc. compressed segments)\r\n- `Matplotlib <https://pypi.org/project/matplotlib/>`_ 3.9.3\r\n (required for plotting)\r\n- `Lxml <https://pypi.org/project/lxml/>`_ 5.3.0\r\n (required only for validating and printing XML)\r\n- `Zarr <https://pypi.org/project/zarr/>`_ 2.18.4\r\n (required only for opening Zarr stores; Zarr 3 is not compatible)\r\n- `Fsspec <https://pypi.org/project/fsspec/>`_ 2024.10.0\r\n (required only for opening ReferenceFileSystem files)\r\n\r\nRevisions\r\n---------\r\n\r\n2024.12.12\r\n\r\n- Pass 5110 tests.\r\n- Read PlaneProperty from STK UIC1Tag (#280).\r\n- Allow 'None' as alias for COMPRESSION.NONE and PREDICTOR.NONE (#274).\r\n- Zarr 3 is not supported (#272).\r\n\r\n2024.9.20\r\n\r\n- Fix writing colormap to ImageJ files (breaking).\r\n- Improve typing.\r\n- Remove support for Python 3.9.\r\n\r\n2024.8.30\r\n\r\n- Support writing OME Dataset and some StructuredAnnotations elements.\r\n\r\n2024.8.28\r\n\r\n- Fix LSM scan types and dimension orders (#269, breaking).\r\n- Use IO[bytes] instead of BinaryIO for typing (#268).\r\n\r\n2024.8.24\r\n\r\n- Do not remove trailing length-1 dimension writing non-shaped file (breaking).\r\n- Fix writing OME-TIFF with certain modulo axes orders.\r\n- Make imshow NaN aware.\r\n\r\n2024.8.10\r\n\r\n- Relax bitspersample check for JPEG, JPEG2K, and JPEGXL compression (#265).\r\n\r\n2024.7.24\r\n\r\n- Fix reading contiguous multi-page series via Zarr store (#67).\r\n\r\n2024.7.21\r\n\r\n- Fix integer overflow in product function caused by numpy types.\r\n- Allow tag reader functions to fail.\r\n\r\n2024.7.2\r\n\r\n- Enable memmap to create empty files with non-native byte order.\r\n- Deprecate Python 3.9, support Python 3.13.\r\n\r\n2024.6.18\r\n\r\n- Ensure TiffPage.nodata is castable to dtype (breaking, #260).\r\n- Support Argos AVS slides.\r\n\r\n2024.5.22\r\n\r\n- Derive TiffPages, TiffPageSeries, FileSequence, StoredShape from Sequence.\r\n- Truncate circular IFD chain, do not raise TiffFileError (breaking).\r\n- Deprecate access to TiffPages.pages and FileSequence.files.\r\n- Enable DeprecationWarning for enums in TIFF namespace.\r\n- Remove some deprecated code (breaking).\r\n- Add iccprofile property to TiffPage and parameter to TiffWriter.write.\r\n- Do not detect VSI as SIS format.\r\n- Limit length of logged exception messages.\r\n- Fix docstring examples not correctly rendered on GitHub (#254, #255).\r\n\r\n2024.5.10\r\n\r\n- Support reading JPEGXL compression in DNG 1.7.\r\n- Read invalid TIFF created by IDEAS software.\r\n\r\n2024.5.3\r\n\r\n- Fix reading incompletely written LSM.\r\n- Fix reading Philips DP with extra rows of tiles (#253, breaking).\r\n\r\n2024.4.24\r\n\r\n- Fix compatibility issue with numpy 2 (#252).\r\n\r\n2024.4.18\r\n\r\n- Fix write_fsspec when last row of tiles is missing in Philips slide (#249).\r\n- Add option not to quote file names in write_fsspec.\r\n- Allow compress bilevel images with deflate, LZMA, and Zstd.\r\n\r\n2024.2.12\r\n\r\n- Deprecate dtype, add chunkdtype parameter in FileSequence.asarray.\r\n- Add imreadargs parameters passed to FileSequence.imread.\r\n\r\n2024.1.30\r\n\r\n- Fix compatibility issue with numpy 2 (#238).\r\n- Enable DeprecationWarning for tuple compression argument.\r\n- Parse sequence of numbers in xml2dict.\r\n\r\n2023.12.9\r\n\r\n- \u2026\r\n\r\nRefer to the CHANGES file for older revisions.\r\n\r\nNotes\r\n-----\r\n\r\nTIFF, the Tagged Image File Format, was created by the Aldus Corporation and\r\nAdobe Systems Incorporated.\r\n\r\nTifffile supports a subset of the TIFF6 specification, mainly 8, 16, 32, and\r\n64-bit integer, 16, 32 and 64-bit float, grayscale and multi-sample images.\r\nSpecifically, CCITT and OJPEG compression, chroma subsampling without JPEG\r\ncompression, color space transformations, samples with differing types, or\r\nIPTC, ICC, and XMP metadata are not implemented.\r\n\r\nBesides classic TIFF, tifffile supports several TIFF-like formats that do not\r\nstrictly adhere to the TIFF6 specification. Some formats allow file and data\r\nsizes to exceed the 4 GB limit of the classic TIFF:\r\n\r\n- **BigTIFF** is identified by version number 43 and uses different file\r\n header, IFD, and tag structures with 64-bit offsets. The format also adds\r\n 64-bit data types. Tifffile can read and write BigTIFF files.\r\n- **ImageJ hyperstacks** store all image data, which may exceed 4 GB,\r\n contiguously after the first IFD. Files > 4 GB contain one IFD only.\r\n The size and shape of the up to 6-dimensional image data can be determined\r\n from the ImageDescription tag of the first IFD, which is Latin-1 encoded.\r\n Tifffile can read and write ImageJ hyperstacks.\r\n- **OME-TIFF** files store up to 8-dimensional image data in one or multiple\r\n TIFF or BigTIFF files. The UTF-8 encoded OME-XML metadata found in the\r\n ImageDescription tag of the first IFD defines the position of TIFF IFDs in\r\n the high dimensional image data. Tifffile can read OME-TIFF files (except\r\n multi-file pyramidal) and write NumPy arrays to single-file OME-TIFF.\r\n- **Micro-Manager NDTiff** stores multi-dimensional image data in one\r\n or more classic TIFF files. Metadata contained in a separate NDTiff.index\r\n binary file defines the position of the TIFF IFDs in the image array.\r\n Each TIFF file also contains metadata in a non-TIFF binary structure at\r\n offset 8. Downsampled image data of pyramidal datasets are stored in\r\n separate folders. Tifffile can read NDTiff files. Version 0 and 1 series,\r\n tiling, stitching, and multi-resolution pyramids are not supported.\r\n- **Micro-Manager MMStack** stores 6-dimensional image data in one or more\r\n classic TIFF files. Metadata contained in non-TIFF binary structures and\r\n JSON strings define the image stack dimensions and the position of the image\r\n frame data in the file and the image stack. The TIFF structures and metadata\r\n are often corrupted or wrong. Tifffile can read MMStack files.\r\n- **Carl Zeiss LSM** files store all IFDs below 4 GB and wrap around 32-bit\r\n StripOffsets pointing to image data above 4 GB. The StripOffsets of each\r\n series and position require separate unwrapping. The StripByteCounts tag\r\n contains the number of bytes for the uncompressed data. Tifffile can read\r\n LSM files of any size.\r\n- **MetaMorph Stack, STK** files contain additional image planes stored\r\n contiguously after the image data of the first page. The total number of\r\n planes is equal to the count of the UIC2tag. Tifffile can read STK files.\r\n- **ZIF**, the Zoomable Image File format, is a subspecification of BigTIFF\r\n with SGI's ImageDepth extension and additional compression schemes.\r\n Only little-endian, tiled, interleaved, 8-bit per sample images with\r\n JPEG, PNG, JPEG XR, and JPEG 2000 compression are allowed. Tifffile can\r\n read and write ZIF files.\r\n- **Hamamatsu NDPI** files use some 64-bit offsets in the file header, IFD,\r\n and tag structures. Single, LONG typed tag values can exceed 32-bit.\r\n The high bytes of 64-bit tag values and offsets are stored after IFD\r\n structures. Tifffile can read NDPI files > 4 GB.\r\n JPEG compressed segments with dimensions >65530 or missing restart markers\r\n cannot be decoded with common JPEG libraries. Tifffile works around this\r\n limitation by separately decoding the MCUs between restart markers, which\r\n performs poorly. BitsPerSample, SamplesPerPixel, and\r\n PhotometricInterpretation tags may contain wrong values, which can be\r\n corrected using the value of tag 65441.\r\n- **Philips TIFF** slides store padded ImageWidth and ImageLength tag values\r\n for tiled pages. The values can be corrected using the DICOM_PIXEL_SPACING\r\n attributes of the XML formatted description of the first page. Tile offsets\r\n and byte counts may be 0. Tifffile can read Philips slides.\r\n- **Ventana/Roche BIF** slides store tiles and metadata in a BigTIFF container.\r\n Tiles may overlap and require stitching based on the TileJointInfo elements\r\n in the XMP tag. Volumetric scans are stored using the ImageDepth extension.\r\n Tifffile can read BIF and decode individual tiles but does not perform\r\n stitching.\r\n- **ScanImage** optionally allows corrupted non-BigTIFF files > 2 GB.\r\n The values of StripOffsets and StripByteCounts can be recovered using the\r\n constant differences of the offsets of IFD and tag values throughout the\r\n file. Tifffile can read such files if the image data are stored contiguously\r\n in each page.\r\n- **GeoTIFF sparse** files allow strip or tile offsets and byte counts to be 0.\r\n Such segments are implicitly set to 0 or the NODATA value on reading.\r\n Tifffile can read GeoTIFF sparse files.\r\n- **Tifffile shaped** files store the array shape and user-provided metadata\r\n of multi-dimensional image series in JSON format in the ImageDescription tag\r\n of the first page of the series. The format allows for multiple series,\r\n SubIFDs, sparse segments with zero offset and byte count, and truncated\r\n series, where only the first page of a series is present, and the image data\r\n are stored contiguously. No other software besides Tifffile supports the\r\n truncated format.\r\n\r\nOther libraries for reading, writing, inspecting, or manipulating scientific\r\nTIFF files from Python are\r\n`aicsimageio <https://pypi.org/project/aicsimageio>`_,\r\n`apeer-ometiff-library\r\n<https://github.com/apeer-micro/apeer-ometiff-library>`_,\r\n`bigtiff <https://pypi.org/project/bigtiff>`_,\r\n`fabio.TiffIO <https://github.com/silx-kit/fabio>`_,\r\n`GDAL <https://github.com/OSGeo/gdal/>`_,\r\n`imread <https://github.com/luispedro/imread>`_,\r\n`large_image <https://github.com/girder/large_image>`_,\r\n`openslide-python <https://github.com/openslide/openslide-python>`_,\r\n`opentile <https://github.com/imi-bigpicture/opentile>`_,\r\n`pylibtiff <https://github.com/pearu/pylibtiff>`_,\r\n`pylsm <https://launchpad.net/pylsm>`_,\r\n`pymimage <https://github.com/ardoi/pymimage>`_,\r\n`python-bioformats <https://github.com/CellProfiler/python-bioformats>`_,\r\n`pytiff <https://github.com/FZJ-INM1-BDA/pytiff>`_,\r\n`scanimagetiffreader-python\r\n<https://gitlab.com/vidriotech/scanimagetiffreader-python>`_,\r\n`SimpleITK <https://github.com/SimpleITK/SimpleITK>`_,\r\n`slideio <https://gitlab.com/bioslide/slideio>`_,\r\n`tiffslide <https://github.com/bayer-science-for-a-better-life/tiffslide>`_,\r\n`tifftools <https://github.com/DigitalSlideArchive/tifftools>`_,\r\n`tyf <https://github.com/Moustikitos/tyf>`_,\r\n`xtiff <https://github.com/BodenmillerGroup/xtiff>`_, and\r\n`ndtiff <https://github.com/micro-manager/NDTiffStorage>`_.\r\n\r\nReferences\r\n----------\r\n\r\n- TIFF 6.0 Specification and Supplements. Adobe Systems Incorporated.\r\n https://www.adobe.io/open/standards/TIFF.html\r\n- TIFF File Format FAQ. https://www.awaresystems.be/imaging/tiff/faq.html\r\n- The BigTIFF File Format.\r\n https://www.awaresystems.be/imaging/tiff/bigtiff.html\r\n- MetaMorph Stack (STK) Image File Format.\r\n http://mdc.custhelp.com/app/answers/detail/a_id/18862\r\n- Image File Format Description LSM 5/7 Release 6.0 (ZEN 2010).\r\n Carl Zeiss MicroImaging GmbH. BioSciences. May 10, 2011\r\n- The OME-TIFF format.\r\n https://docs.openmicroscopy.org/ome-model/latest/\r\n- UltraQuant(r) Version 6.0 for Windows Start-Up Guide.\r\n http://www.ultralum.com/images%20ultralum/pdf/UQStart%20Up%20Guide.pdf\r\n- Micro-Manager File Formats.\r\n https://micro-manager.org/wiki/Micro-Manager_File_Formats\r\n- ScanImage BigTiff Specification.\r\n https://docs.scanimage.org/Appendix/ScanImage+BigTiff+Specification.html\r\n- ZIF, the Zoomable Image File format. https://zif.photo/\r\n- GeoTIFF File Format https://gdal.org/drivers/raster/gtiff.html\r\n- Cloud optimized GeoTIFF.\r\n https://github.com/cogeotiff/cog-spec/blob/master/spec.md\r\n- Tags for TIFF and Related Specifications. Digital Preservation.\r\n https://www.loc.gov/preservation/digital/formats/content/tiff_tags.shtml\r\n- CIPA DC-008-2016: Exchangeable image file format for digital still cameras:\r\n Exif Version 2.31.\r\n http://www.cipa.jp/std/documents/e/DC-008-Translation-2016-E.pdf\r\n- The EER (Electron Event Representation) file format.\r\n https://github.com/fei-company/EerReaderLib\r\n- Digital Negative (DNG) Specification. Version 1.7.1.0, September 2023.\r\n https://helpx.adobe.com/content/dam/help/en/photoshop/pdf/DNG_Spec_1_7_1_0.pdf\r\n- Roche Digital Pathology. BIF image file format for digital pathology.\r\n https://diagnostics.roche.com/content/dam/diagnostics/Blueprint/en/pdf/rmd/Roche-Digital-Pathology-BIF-Whitepaper.pdf\r\n- Astro-TIFF specification. https://astro-tiff.sourceforge.io/\r\n- Aperio Technologies, Inc. Digital Slides and Third-Party Data Interchange.\r\n Aperio_Digital_Slides_and_Third-party_data_interchange.pdf\r\n- PerkinElmer image format.\r\n https://downloads.openmicroscopy.org/images/Vectra-QPTIFF/perkinelmer/PKI_Image%20Format.docx\r\n- NDTiffStorage. https://github.com/micro-manager/NDTiffStorage\r\n- Argos AVS File Format.\r\n https://github.com/user-attachments/files/15580286/ARGOS.AVS.File.Format.pdf\r\n\r\nExamples\r\n--------\r\n\r\nWrite a NumPy array to a single-page RGB TIFF file:\r\n\r\n>>> data = numpy.random.randint(0, 255, (256, 256, 3), 'uint8')\r\n>>> imwrite('temp.tif', data, photometric='rgb')\r\n\r\nRead the image from the TIFF file as NumPy array:\r\n\r\n>>> image = imread('temp.tif')\r\n>>> image.shape\r\n(256, 256, 3)\r\n\r\nUse the `photometric` and `planarconfig` arguments to write a 3x3x3 NumPy\r\narray to an interleaved RGB, a planar RGB, or a 3-page grayscale TIFF:\r\n\r\n>>> data = numpy.random.randint(0, 255, (3, 3, 3), 'uint8')\r\n>>> imwrite('temp.tif', data, photometric='rgb')\r\n>>> imwrite('temp.tif', data, photometric='rgb', planarconfig='separate')\r\n>>> imwrite('temp.tif', data, photometric='minisblack')\r\n\r\nUse the `extrasamples` argument to specify how extra components are\r\ninterpreted, for example, for an RGBA image with unassociated alpha channel:\r\n\r\n>>> data = numpy.random.randint(0, 255, (256, 256, 4), 'uint8')\r\n>>> imwrite('temp.tif', data, photometric='rgb', extrasamples=['unassalpha'])\r\n\r\nWrite a 3-dimensional NumPy array to a multi-page, 16-bit grayscale TIFF file:\r\n\r\n>>> data = numpy.random.randint(0, 2**12, (64, 301, 219), 'uint16')\r\n>>> imwrite('temp.tif', data, photometric='minisblack')\r\n\r\nRead the whole image stack from the multi-page TIFF file as NumPy array:\r\n\r\n>>> image_stack = imread('temp.tif')\r\n>>> image_stack.shape\r\n(64, 301, 219)\r\n>>> image_stack.dtype\r\ndtype('uint16')\r\n\r\nRead the image from the first page in the TIFF file as NumPy array:\r\n\r\n>>> image = imread('temp.tif', key=0)\r\n>>> image.shape\r\n(301, 219)\r\n\r\nRead images from a selected range of pages:\r\n\r\n>>> images = imread('temp.tif', key=range(4, 40, 2))\r\n>>> images.shape\r\n(18, 301, 219)\r\n\r\nIterate over all pages in the TIFF file and successively read images:\r\n\r\n>>> with TiffFile('temp.tif') as tif:\r\n... for page in tif.pages:\r\n... image = page.asarray()\r\n...\r\n\r\nGet information about the image stack in the TIFF file without reading\r\nany image data:\r\n\r\n>>> tif = TiffFile('temp.tif')\r\n>>> len(tif.pages) # number of pages in the file\r\n64\r\n>>> page = tif.pages[0] # get shape and dtype of image in first page\r\n>>> page.shape\r\n(301, 219)\r\n>>> page.dtype\r\ndtype('uint16')\r\n>>> page.axes\r\n'YX'\r\n>>> series = tif.series[0] # get shape and dtype of first image series\r\n>>> series.shape\r\n(64, 301, 219)\r\n>>> series.dtype\r\ndtype('uint16')\r\n>>> series.axes\r\n'QYX'\r\n>>> tif.close()\r\n\r\nInspect the \"XResolution\" tag from the first page in the TIFF file:\r\n\r\n>>> with TiffFile('temp.tif') as tif:\r\n... tag = tif.pages[0].tags['XResolution']\r\n...\r\n>>> tag.value\r\n(1, 1)\r\n>>> tag.name\r\n'XResolution'\r\n>>> tag.code\r\n282\r\n>>> tag.count\r\n1\r\n>>> tag.dtype\r\n<DATATYPE.RATIONAL: 5>\r\n\r\nIterate over all tags in the TIFF file:\r\n\r\n>>> with TiffFile('temp.tif') as tif:\r\n... for page in tif.pages:\r\n... for tag in page.tags:\r\n... tag_name, tag_value = tag.name, tag.value\r\n...\r\n\r\nOverwrite the value of an existing tag, for example, XResolution:\r\n\r\n>>> with TiffFile('temp.tif', mode='r+') as tif:\r\n... _ = tif.pages[0].tags['XResolution'].overwrite((96000, 1000))\r\n...\r\n\r\nWrite a 5-dimensional floating-point array using BigTIFF format, separate\r\ncolor components, tiling, Zlib compression level 8, horizontal differencing\r\npredictor, and additional metadata:\r\n\r\n>>> data = numpy.random.rand(2, 5, 3, 301, 219).astype('float32')\r\n>>> imwrite(\r\n... 'temp.tif',\r\n... data,\r\n... bigtiff=True,\r\n... photometric='rgb',\r\n... planarconfig='separate',\r\n... tile=(32, 32),\r\n... compression='zlib',\r\n... compressionargs={'level': 8},\r\n... predictor=True,\r\n... metadata={'axes': 'TZCYX'},\r\n... )\r\n\r\nWrite a 10 fps time series of volumes with xyz voxel size 2.6755x2.6755x3.9474\r\nmicron^3 to an ImageJ hyperstack formatted TIFF file:\r\n\r\n>>> volume = numpy.random.randn(6, 57, 256, 256).astype('float32')\r\n>>> image_labels = [f'{i}' for i in range(volume.shape[0] * volume.shape[1])]\r\n>>> imwrite(\r\n... 'temp.tif',\r\n... volume,\r\n... imagej=True,\r\n... resolution=(1.0 / 2.6755, 1.0 / 2.6755),\r\n... metadata={\r\n... 'spacing': 3.947368,\r\n... 'unit': 'um',\r\n... 'finterval': 1 / 10,\r\n... 'fps': 10.0,\r\n... 'axes': 'TZYX',\r\n... 'Labels': image_labels,\r\n... },\r\n... )\r\n\r\nRead the volume and metadata from the ImageJ hyperstack file:\r\n\r\n>>> with TiffFile('temp.tif') as tif:\r\n... volume = tif.asarray()\r\n... axes = tif.series[0].axes\r\n... imagej_metadata = tif.imagej_metadata\r\n...\r\n>>> volume.shape\r\n(6, 57, 256, 256)\r\n>>> axes\r\n'TZYX'\r\n>>> imagej_metadata['slices']\r\n57\r\n>>> imagej_metadata['frames']\r\n6\r\n\r\nMemory-map the contiguous image data in the ImageJ hyperstack file:\r\n\r\n>>> memmap_volume = memmap('temp.tif')\r\n>>> memmap_volume.shape\r\n(6, 57, 256, 256)\r\n>>> del memmap_volume\r\n\r\nCreate a TIFF file containing an empty image and write to the memory-mapped\r\nNumPy array (note: this does not work with compression or tiling):\r\n\r\n>>> memmap_image = memmap(\r\n... 'temp.tif', shape=(256, 256, 3), dtype='float32', photometric='rgb'\r\n... )\r\n>>> type(memmap_image)\r\n<class 'numpy.memmap'>\r\n>>> memmap_image[255, 255, 1] = 1.0\r\n>>> memmap_image.flush()\r\n>>> del memmap_image\r\n\r\nWrite two NumPy arrays to a multi-series TIFF file (note: other TIFF readers\r\nwill not recognize the two series; use the OME-TIFF format for better\r\ninteroperability):\r\n\r\n>>> series0 = numpy.random.randint(0, 255, (32, 32, 3), 'uint8')\r\n>>> series1 = numpy.random.randint(0, 255, (4, 256, 256), 'uint16')\r\n>>> with TiffWriter('temp.tif') as tif:\r\n... tif.write(series0, photometric='rgb')\r\n... tif.write(series1, photometric='minisblack')\r\n...\r\n\r\nRead the second image series from the TIFF file:\r\n\r\n>>> series1 = imread('temp.tif', series=1)\r\n>>> series1.shape\r\n(4, 256, 256)\r\n\r\nSuccessively write the frames of one contiguous series to a TIFF file:\r\n\r\n>>> data = numpy.random.randint(0, 255, (30, 301, 219), 'uint8')\r\n>>> with TiffWriter('temp.tif') as tif:\r\n... for frame in data:\r\n... tif.write(frame, contiguous=True)\r\n...\r\n\r\nAppend an image series to the existing TIFF file (note: this does not work\r\nwith ImageJ hyperstack or OME-TIFF files):\r\n\r\n>>> data = numpy.random.randint(0, 255, (301, 219, 3), 'uint8')\r\n>>> imwrite('temp.tif', data, photometric='rgb', append=True)\r\n\r\nCreate a TIFF file from a generator of tiles:\r\n\r\n>>> data = numpy.random.randint(0, 2**12, (31, 33, 3), 'uint16')\r\n>>> def tiles(data, tileshape):\r\n... for y in range(0, data.shape[0], tileshape[0]):\r\n... for x in range(0, data.shape[1], tileshape[1]):\r\n... yield data[y : y + tileshape[0], x : x + tileshape[1]]\r\n...\r\n>>> imwrite(\r\n... 'temp.tif',\r\n... tiles(data, (16, 16)),\r\n... tile=(16, 16),\r\n... shape=data.shape,\r\n... dtype=data.dtype,\r\n... photometric='rgb',\r\n... )\r\n\r\nWrite a multi-dimensional, multi-resolution (pyramidal), multi-series OME-TIFF\r\nfile with optional metadata. Sub-resolution images are written to SubIFDs.\r\nLimit parallel encoding to 2 threads. Write a thumbnail image as a separate\r\nimage series:\r\n\r\n>>> data = numpy.random.randint(0, 255, (8, 2, 512, 512, 3), 'uint8')\r\n>>> subresolutions = 2\r\n>>> pixelsize = 0.29 # micrometer\r\n>>> with TiffWriter('temp.ome.tif', bigtiff=True) as tif:\r\n... metadata = {\r\n... 'axes': 'TCYXS',\r\n... 'SignificantBits': 8,\r\n... 'TimeIncrement': 0.1,\r\n... 'TimeIncrementUnit': 's',\r\n... 'PhysicalSizeX': pixelsize,\r\n... 'PhysicalSizeXUnit': '\u00b5m',\r\n... 'PhysicalSizeY': pixelsize,\r\n... 'PhysicalSizeYUnit': '\u00b5m',\r\n... 'Channel': {'Name': ['Channel 1', 'Channel 2']},\r\n... 'Plane': {'PositionX': [0.0] * 16, 'PositionXUnit': ['\u00b5m'] * 16},\r\n... 'Description': 'A multi-dimensional, multi-resolution image',\r\n... 'MapAnnotation': { # for OMERO\r\n... 'Namespace': 'openmicroscopy.org/PyramidResolution',\r\n... '1': '256 256',\r\n... '2': '128 128',\r\n... },\r\n... }\r\n... options = dict(\r\n... photometric='rgb',\r\n... tile=(128, 128),\r\n... compression='jpeg',\r\n... resolutionunit='CENTIMETER',\r\n... maxworkers=2,\r\n... )\r\n... tif.write(\r\n... data,\r\n... subifds=subresolutions,\r\n... resolution=(1e4 / pixelsize, 1e4 / pixelsize),\r\n... metadata=metadata,\r\n... **options,\r\n... )\r\n... # write pyramid levels to the two subifds\r\n... # in production use resampling to generate sub-resolution images\r\n... for level in range(subresolutions):\r\n... mag = 2 ** (level + 1)\r\n... tif.write(\r\n... data[..., ::mag, ::mag, :],\r\n... subfiletype=1,\r\n... resolution=(1e4 / mag / pixelsize, 1e4 / mag / pixelsize),\r\n... **options,\r\n... )\r\n... # add a thumbnail image as a separate series\r\n... # it is recognized by QuPath as an associated image\r\n... thumbnail = (data[0, 0, ::8, ::8] >> 2).astype('uint8')\r\n... tif.write(thumbnail, metadata={'Name': 'thumbnail'})\r\n...\r\n\r\nAccess the image levels in the pyramidal OME-TIFF file:\r\n\r\n>>> baseimage = imread('temp.ome.tif')\r\n>>> second_level = imread('temp.ome.tif', series=0, level=1)\r\n>>> with TiffFile('temp.ome.tif') as tif:\r\n... baseimage = tif.series[0].asarray()\r\n... second_level = tif.series[0].levels[1].asarray()\r\n... number_levels = len(tif.series[0].levels) # includes base level\r\n...\r\n\r\nIterate over and decode single JPEG compressed tiles in the TIFF file:\r\n\r\n>>> with TiffFile('temp.ome.tif') as tif:\r\n... fh = tif.filehandle\r\n... for page in tif.pages:\r\n... for index, (offset, bytecount) in enumerate(\r\n... zip(page.dataoffsets, page.databytecounts)\r\n... ):\r\n... _ = fh.seek(offset)\r\n... data = fh.read(bytecount)\r\n... tile, indices, shape = page.decode(\r\n... data, index, jpegtables=page.jpegtables\r\n... )\r\n...\r\n\r\nUse Zarr 2 to read parts of the tiled, pyramidal images in the TIFF file:\r\n\r\n>>> import zarr\r\n>>> store = imread('temp.ome.tif', aszarr=True)\r\n>>> z = zarr.open(store, mode='r')\r\n>>> z\r\n<zarr.hierarchy.Group '/' read-only>\r\n>>> z[0] # base layer\r\n<zarr.core.Array '/0' (8, 2, 512, 512, 3) uint8 read-only>\r\n>>> z[0][2, 0, 128:384, 256:].shape # read a tile from the base layer\r\n(256, 256, 3)\r\n>>> store.close()\r\n\r\nLoad the base layer from the Zarr 2 store as a dask array:\r\n\r\n>>> import dask.array\r\n>>> store = imread('temp.ome.tif', aszarr=True)\r\n>>> dask.array.from_zarr(store, 0)\r\ndask.array<...shape=(8, 2, 512, 512, 3)...chunksize=(1, 1, 128, 128, 3)...\r\n>>> store.close()\r\n\r\nWrite the Zarr 2 store to a fsspec ReferenceFileSystem in JSON format:\r\n\r\n>>> store = imread('temp.ome.tif', aszarr=True)\r\n>>> store.write_fsspec('temp.ome.tif.json', url='file://')\r\n>>> store.close()\r\n\r\nOpen the fsspec ReferenceFileSystem as a Zarr group:\r\n\r\n>>> import fsspec\r\n>>> import imagecodecs.numcodecs\r\n>>> imagecodecs.numcodecs.register_codecs()\r\n>>> mapper = fsspec.get_mapper(\r\n... 'reference://', fo='temp.ome.tif.json', target_protocol='file'\r\n... )\r\n>>> z = zarr.open(mapper, mode='r')\r\n>>> z\r\n<zarr.hierarchy.Group '/' read-only>\r\n\r\nCreate an OME-TIFF file containing an empty, tiled image series and write\r\nto it via the Zarr interface (note: this does not work with compression):\r\n\r\n>>> imwrite(\r\n... 'temp2.ome.tif',\r\n... shape=(8, 800, 600),\r\n... dtype='uint16',\r\n... photometric='minisblack',\r\n... tile=(128, 128),\r\n... metadata={'axes': 'CYX'},\r\n... )\r\n>>> store = imread('temp2.ome.tif', mode='r+', aszarr=True)\r\n>>> z = zarr.open(store, mode='r+')\r\n>>> z\r\n<zarr.core.Array (8, 800, 600) uint16>\r\n>>> z[3, 100:200, 200:300:2] = 1024\r\n>>> store.close()\r\n\r\nRead images from a sequence of TIFF files as NumPy array using two I/O worker\r\nthreads:\r\n\r\n>>> imwrite('temp_C001T001.tif', numpy.random.rand(64, 64))\r\n>>> imwrite('temp_C001T002.tif', numpy.random.rand(64, 64))\r\n>>> image_sequence = imread(\r\n... ['temp_C001T001.tif', 'temp_C001T002.tif'], ioworkers=2, maxworkers=1\r\n... )\r\n>>> image_sequence.shape\r\n(2, 64, 64)\r\n>>> image_sequence.dtype\r\ndtype('float64')\r\n\r\nRead an image stack from a series of TIFF files with a file name pattern\r\nas NumPy or Zarr arrays:\r\n\r\n>>> image_sequence = TiffSequence('temp_C0*.tif', pattern=r'_(C)(\\d+)(T)(\\d+)')\r\n>>> image_sequence.shape\r\n(1, 2)\r\n>>> image_sequence.axes\r\n'CT'\r\n>>> data = image_sequence.asarray()\r\n>>> data.shape\r\n(1, 2, 64, 64)\r\n>>> store = image_sequence.aszarr()\r\n>>> zarr.open(store, mode='r')\r\n<zarr.core.Array (1, 2, 64, 64) float64 read-only>\r\n>>> image_sequence.close()\r\n\r\nWrite the Zarr 2 store to a fsspec ReferenceFileSystem in JSON format:\r\n\r\n>>> store = image_sequence.aszarr()\r\n>>> store.write_fsspec('temp.json', url='file://')\r\n\r\nOpen the fsspec ReferenceFileSystem as a Zarr array:\r\n\r\n>>> import fsspec\r\n>>> import tifffile.numcodecs\r\n>>> tifffile.numcodecs.register_codec()\r\n>>> mapper = fsspec.get_mapper(\r\n... 'reference://', fo='temp.json', target_protocol='file'\r\n... )\r\n>>> zarr.open(mapper, mode='r')\r\n<zarr.core.Array (1, 2, 64, 64) float64 read-only>\r\n\r\nInspect the TIFF file from the command line::\r\n\r\n $ python -m tifffile temp.ome.tif\r\n",
"bugtrack_url": null,
"license": "BSD",
"summary": "Read and write TIFF files",
"version": "2024.12.12",
"project_urls": {
"Bug Tracker": "https://github.com/cgohlke/tifffile/issues",
"Homepage": "https://www.cgohlke.com",
"Source Code": "https://github.com/cgohlke/tifffile"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "d81e76cbc758f6865a9da18001ac70d1a4154603b71e233f704401fc7d62493e",
"md5": "94f1805c93f82a83161c04ee2a89bcb2",
"sha256": "6ff0f196a46a75c8c0661c70995e06ea4d08a81fe343193e69f1673f4807d508"
},
"downloads": -1,
"filename": "tifffile-2024.12.12-py3-none-any.whl",
"has_sig": false,
"md5_digest": "94f1805c93f82a83161c04ee2a89bcb2",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10",
"size": 227538,
"upload_time": "2024-12-13T02:05:13",
"upload_time_iso_8601": "2024-12-13T02:05:13.974060Z",
"url": "https://files.pythonhosted.org/packages/d8/1e/76cbc758f6865a9da18001ac70d1a4154603b71e233f704401fc7d62493e/tifffile-2024.12.12-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "37c9fc4e490c5b0ccad68c98ea1d6e0f409bd7d50e2e8fc30a0725594d3104ff",
"md5": "39fb043b0752f9637fc4b692b65e3876",
"sha256": "c38e929bf74c04b6c8708d87f16b32c85c6d7c2514b99559ea3db8003ba4edda"
},
"downloads": -1,
"filename": "tifffile-2024.12.12.tar.gz",
"has_sig": false,
"md5_digest": "39fb043b0752f9637fc4b692b65e3876",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10",
"size": 365416,
"upload_time": "2024-12-13T02:05:16",
"upload_time_iso_8601": "2024-12-13T02:05:16.730284Z",
"url": "https://files.pythonhosted.org/packages/37/c9/fc4e490c5b0ccad68c98ea1d6e0f409bd7d50e2e8fc30a0725594d3104ff/tifffile-2024.12.12.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-12-13 02:05:16",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "cgohlke",
"github_project": "tifffile",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "tifffile"
}