..
  This file is generated by setup.py

Read Carl Zeiss image files (CZI)
=================================

Czifile is a Python library to read Carl Zeiss Image (CZI) files, the native
file format of the ZEN(r) software by Carl Zeiss Microscopy GmbH. CZI files
contain multidimensional images and metadata from microscopy experiments.

:Author: `Christoph Gohlke <https://www.cgohlke.com>`_
:License: BSD-3-Clause
:Version: 2026.3.12
:DOI: `10.5281/zenodo.14948581 <https://doi.org/10.5281/zenodo.14948581>`_

Quickstart
----------

Install the czifile package and all dependencies from the
`Python Package Index <https://pypi.org/project/czifile/>`_::

    python -m pip install -U czifile[all]

See `Examples`_ for using the programming interface.

Source code, examples, and support are available on
`GitHub <https://github.com/cgohlke/czifile>`_.

Requirements
------------

This revision was tested with the following requirements and dependencies
(other versions may work):

- `CPython <https://www.python.org>`_ 3.12.10, 3.13.12, 3.14.3 64-bit
- `NumPy <https://pypi.org/project/numpy>`_ 2.4.2
- `Imagecodecs <https://pypi.org/project/imagecodecs>`_ 2025.3.30
  (required for decoding LZW, JPEG XR, Zstd, etc.)
- `Xarray <https://pypi.org/project/xarray>`_ 2026.2.0 (recommended)
- `Matplotlib <https://pypi.org/project/matplotlib/>`_ 3.10.8 (optional)
- `Tifffile <https://pypi.org/project/tifffile/>`_ 2026.3.3 (optional)

Revisions
---------

2026.3.12

- Rewrite with many breaking changes.
- Support Zstd compression schemes.
- Support reading subblock masks.
- Add CziFile.scene interface.
- Add pyramid level access via CziImage.levels.
- Add option to read subset of image data.
- Add option to iterate over image planes in any dimension order.
- Add xarray-style attributes.
- Add asxarray method to return image as xarray DataArray with metadata.
- Add fillvalue and maxworkers parameters to asarray.
- Add option to specify pixel type.
- Promote pixel type when channels have mixed types.
- Remove Mosaic dimension from CziDirectoryEntryDV.dims; use mosaic_index.
- Reduce caching of CziDirectoryEntryDV properties.
- Remove resize and order parameters from asarray (breaking).
- Remove czi2tif function and command line script.
- Prefix public class names with Czi.
- Raise CziFileError for issues with CZI file structure.
- Use logging instead of warnings.
- Improve representation of instances.
- Add pytest-based unit tests.
- Add type hints.
- Convert docstrings to Google style with Sphinx directives.
- Remove imagecodecs-lite fallback; require imagecodecs.
- Remove scipy/ndimage dependency.
- Make tifffile an optional dependency.
- Drop support for Python < 3.12 and numpy < 2 (SPEC 0).

2019.7.2.3

- …

Refer to the CHANGES file for older revisions.

Notes
-----

The API is not stable yet and might change between revisions.

Python 32-bit versions are deprecated. Python < 3.12 are no longer supported.

"ZEISS" and "Carl Zeiss" are registered trademarks of Carl Zeiss AG.

The ZISRAW file format design specification [1] is confidential and the
license agreement does not permit to write data into CZI files.

Only a subset of the 2016 specification is implemented. Specifically,
multi-file images and topography images are not supported.
Some features are untested due to lack of sample files.

Tested on Windows with a few example files only.

Czifile relies on the `imagecodecs <https://pypi.org/project/imagecodecs/>`__
package for decoding LZW, ZStandard, JPEG, and JPEG XR compressed images.

Other libraries for reading CZI files (all GPL or LGPL licensed):
`libczi <https://github.com/ZEISS/libczi>`__,
`pylibCZIrw <https://pypi.org/project/pylibCZIrw>`__,
`bioio-czi <https://github.com/bioio-devs/bioio-czi>`__,
`bio-formats <https://github.com/ome/bioformats>`_,
`libCZI <https://github.com/zeiss-microscopy/libCZI>`__ (deprecated), and
`pylibczi <https://github.com/elhuhdron/pylibczi>`__ (deprecated).

Compared to pylibCZIrw, which wraps the C++ libczi library under LGPL,
czifile is a pure-Python, permissively BSD-licensed reader.
Czifile provides direct access to every ZISRAW segment (raw subblock bytes,
per-subblock XML metadata, and subblock binary attachments), full decoding
of all file-level attachment types (TimeStamps, EventList, LookupTables,
FocusPositions, embedded thumbnails, and recursive CZI files),
correct AiryScan fast-scan upsampling, correct stitching of single-point
time-series/sFCS subblocks along T, explicit pyramid-level objects,
flexible per-dimension selection and reordering, efficient single-call
multi-dimensional array access to scenes and spatial ROIs,
and ``xarray.DataArray`` output with physical axis coordinates
(spatial, temporal, and spectral).
pylibCZIrw's main advantages are writing CZI files, a configurable
subblock cache, fractional-zoom pyramid access, resource efficiency,
and lower per-call overhead for single-subblock reads (however,
with multiple threads, czifile may match or exceed pylibCZIrw throughput).

References
----------

1. ZISRAW (CZI) File Format Design Specification Release Version 1.2.2.
   "CZI 07-2016/CZI-DOC ZEN 2.3/DS_ZISRAW-FileFormat.pdf" (confidential).

Examples
--------

Read image data of the first scene from a CZI file as numpy array:

.. code-block:: python

    >>> image = imread('Example.czi')
    >>> assert image.shape == (2, 2, 3, 486, 1178)
    >>> assert image.dtype == 'uint16'

Access scenes, shape, and metadata:

.. code-block:: python

    >>> with CziFile('Example.czi') as czi:
    ...     assert len(czi.scenes) == 3
    ...     img = czi.scenes[0]  # 0 is the absolute coordinate of the first scene
    ...     assert img.shape == (2, 2, 3, 486, 1178)
    ...     assert img.dims == ('T', 'C', 'Z', 'Y', 'X')
    ...     assert img.dtype == 'uint16'
    ...     assert img.compression.name == 'ZSTDHDR'
    ...     assert list(img.channels) == ['DAPI', 'EGFP']
    ...     assert czi.metadata().startswith('<ImageDocument>')
    ...

Select dimensions and read as numpy array:

.. code-block:: python

    >>> with CziFile('Example.czi') as czi:
    ...     img = czi.scenes[0]
    ...     assert img.sizes == {'T': 2, 'C': 2, 'Z': 3, 'Y': 486, 'X': 1178}
    ...
    ...     # integer selection: fix T=0 and C=0; result has Z, but no T or C axis
    ...     volume = img(T=0, C=0).asarray()
    ...     assert volume.shape == (3, 486, 1178)
    ...
    ...     # None selection: keep all values but reorder dimensions
    ...     # dims order follows the kwargs order, then spatial dims
    ...     # T (unspecified) comes first, then C, Z (in kwargs order), then Y X
    ...     tczyx = img(C=None, Z=None).asarray()
    ...     assert tczyx.shape == (2, 2, 3, 486, 1178)
    ...
    ...     # read in C-outer, Z-inner, T-innermost order with parallelism
    ...     arr = img(C=None, Z=None, T=None).asarray(maxworkers=8)
    ...     assert arr.shape == (2, 3, 2, 486, 1178)  # 'C', 'Z', 'T', 'Y', 'X'
    ...
    ...     # img.bbox gives (x, y, width, height) in global CZI coordinates
    ...     x0, y0, *_ = img.bbox
    ...     plane_roi = img(T=0, C=0, roi=(x0, y0, 128, 128)).asarray()
    ...     assert plane_roi.shape == (3, 128, 128)  # 'Z', 'Y', 'X'
    ...
    ...     # fill pixels outside subblock coverage with a specific value
    ...     padded = img(C=0, roi=(0, 0, 2048, 2048)).asarray(fillvalue=0)
    ...     assert padded.shape == (2, 3, 2048, 2048)  # 'T', 'Z', 'Y', 'X'
    ...

Iterate individual Y/X planes:

.. code-block:: python

    >>> with CziFile('Example.czi') as czi:
    ...     img = czi.scenes[0]
    ...
    ...     # img has non-spatial dims T, C, Z
    ...     # unspecified dims (T) come first, then kwargs order (C, Z)
    ...     # iterates T-outer, C-middle, Z-inner
    ...     for plane in img(C=None, Z=None).planes:
    ...         assert plane.shape == (486, 1178)
    ...
    ...     # iterate with absolute coordinate values
    ...     for coords, plane in img(C=None, Z=None).planes.items():
    ...         assert plane.shape == (486, 1178)
    ...         assert len(coords) == 3  # (t_coord, c_coord, z_coord)
    ...
    ...     # assemble a full array plane-by-plane (equivalent to asarray(),
    ...     # but much slower - use asarray() for bulk reads):
    ...     # spatial dims are always last, so zip truncates at len(coords),
    ...     # skipping Y/X from sel.start and converting to 0-based positions.
    ...     sel = img(C=None, Z=None)
    ...     out = numpy.empty(sel.shape, sel.dtype)
    ...     for coords, plane in sel.planes.items():
    ...         out[tuple(i - j for i, j in zip(coords, sel.start))] = plane
    ...     assert_array_equal(out, sel.asarray())
    ...
    ...     # indexed access: pass the same absolute coordinate values
    ...     # that .planes.items() / .planes.keys() returns
    ...     plane = img(C=None, Z=None).planes[0, 0, 0]  # T=0, C=0, Z=0
    ...     assert plane.shape == (486, 1178)
    ...

Read image as xarray DataArray with physical coordinates and attributes:

.. code-block:: python

    >>> with CziFile('Example.czi') as czi:
    ...     xarr = czi.scenes[0].asxarray()
    ...     assert xarr.name == 'Scene 0'
    ...     assert xarr.sizes == {'T': 2, 'C': 2, 'Z': 3, 'Y': 486, 'X': 1178}
    ...     assert xarr.coords['X'].size == 1178  # physical axis coordinates
    ...

Access multiple scenes:

.. code-block:: python

    >>> with CziFile('Example.czi') as czi:
    ...     # iterate scenes individually and read as arrays
    ...     for scene in czi.scenes.values():
    ...         arr = scene.asarray()
    ...
    ...     # query which scenes (indices) are available
    ...     assert list(czi.scenes.keys()) == [0, 1, 2]
    ...
    ...     # select the second scene
    ...     assert czi.scenes[1].sizes == {
    ...         'T': 2,
    ...         'C': 2,
    ...         'Z': 3,
    ...         'Y': 256,
    ...         'X': 256,
    ...     }
    ...
    ...     # merge selected scenes into one
    ...     scenes = czi.scenes(scene=[0, 1])  # first 2 scenes
    ...     assert scenes.sizes == {'T': 2, 'C': 2, 'Z': 3, 'Y': 1109, 'X': 1760}
    ...
    ...     # merge all scenes into one
    ...     scenes = czi.scenes()
    ...     assert scenes.sizes == {'T': 2, 'C': 2, 'Z': 3, 'Y': 2055, 'X': 2581}
    ...

Access pyramid levels:

.. code-block:: python

    >>> with CziFile('Example.czi') as czi:
    ...     img = czi.scenes[0]
    ...     assert img.is_pyramid
    ...     assert len(img.levels) == 2  # full resolution + 1 downsampled level
    ...     assert img.levels[0] is img  # full resolution level is the same as img
    ...     overview = img.levels[1]  # lowest-res level
    ...     assert overview.sizes == {'T': 2, 'C': 2, 'Z': 3, 'Y': 243, 'X': 589}
    ...

Access attachments:

.. code-block:: python

    >>> with CziFile('Example.czi') as czi:
    ...     for attachment in czi.attachments():
    ...         name = attachment.attachment_entry.name
    ...         data = attachment.data()  # decoded (ndarray, tuple, bytes...)
    ...         raw = attachment.data(raw=True)  # always bytes
    ...
    ...     # convenience shortcut for TimeStamps attachment data
    ...     assert czi.timestamps.shape == (2,)
    ...

Low-level access to CZI file segments:

.. code-block:: python

    >>> with CziFile('Example.czi') as czi:
    ...     # file header: version, GUIDs, and segment offsets
    ...     hdr = czi.header
    ...     assert hdr.version == (1, 0)
    ...     assert str(hdr.file_guid) == 'f8a61493-053e-c94e-bae0-bc7e96d18997'
    ...     assert not hdr.update_pending
    ...
    ...     # iterate all subblock segments sequentially via the directory
    ...     for sb in czi.subblocks():
    ...         entry = sb.directory_entry
    ...         assert entry.dims == ('H', 'T', 'C', 'Z', 'Y', 'X', 'S')
    ...         assert entry.start == (0, 0, 0, 0, 0, 582, 0)
    ...         assert entry.shape == (1, 1, 1, 1, 486, 1178, 1)
    ...         assert entry.stored_shape == (1, 1, 1, 1, 243, 589, 1)
    ...         assert entry.compression == CziCompressionType.ZSTDHDR
    ...         assert sb.data().shape == (1, 1, 1, 1, 243, 589, 1)  # stored_shape
    ...         assert isinstance(sb.data(raw=True), bytes)
    ...         assert sb.metadata().startswith('<METADATA>')
    ...         break  # just the first subblock segment for demonstration
    ...
    ...     # walk all file segments by type using their ZISRAW segment IDs
    ...     for segdata in czi.segments(CziSegmentId.ZISRAWSUBBLOCK):
    ...         assert isinstance(segdata, CziSubBlockSegmentData)
    ...
    ...     # direct low-level segment header at a known file offset
    ...     seg = CziSegment(czi, czi.header.directory_position)
    ...     assert seg.sid == CziSegmentId.ZISRAWDIRECTORY
    ...     assert seg.used_size == 68768
    ...     seg_data = seg.data()
    ...     assert isinstance(seg_data, CziSubBlockDirectorySegmentData)
    ...

View the images and metadata in a CZI file from the console::

    $ python -m czifile Example.czi