Metadata-Version: 2.4
Name: czifile
Version: 2026.3.14
Summary: Read Carl Zeiss image files (CZI)
Home-page: https://www.cgohlke.com
Author: Christoph Gohlke
Author-email: cgohlke@cgohlke.com
License: BSD-3-Clause
Project-URL: Bug Tracker, https://github.com/cgohlke/czifile/issues
Project-URL: Source Code, https://github.com/cgohlke/czifile
Platform: any
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Python: >=3.12
Description-Content-Type: text/x-rst
License-File: LICENSE
Requires-Dist: numpy>=2.0
Requires-Dist: imagecodecs>=2026.3.6
Provides-Extra: all
Requires-Dist: xarray; extra == "all"
Requires-Dist: tifffile; extra == "all"
Requires-Dist: matplotlib; extra == "all"
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: license
Dynamic: license-file
Dynamic: platform
Dynamic: project-url
Dynamic: provides-extra
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

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

Czifile is a Python library for reading image data and metadata from
Carl Zeiss Image (CZI) files, the native file format of ZEN by
Carl Zeiss Microscopy GmbH.

- Pure-Python implementation under BSD-3-Clause license.
- Single-call array access to scenes and spatial ROIs.
- Xarray DataArray output with physical axis coordinates.
- Multi-scene merging into a single array.
- Per-dimension selection with integer, slice, and list indexing.
- Plane-by-plane iterator.
- Pyramid-level access for multi-resolution images.
- Tile upsampling (Fast Airyscan), downsampling (PALM), and stitching
  (single-point FCS) with optional stored-resolution output.
- Support for compression schemes (Zstd and JPEG XR) and
  pixel type promotion across channels.
- Direct access to every ZISRAW segment and file-level attachments.

:Author: `Christoph Gohlke <https://www.cgohlke.com>`_
:License: BSD-3-Clause
:Version: 2026.3.14
: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>`_ 2026.3.6
  (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.14

- Add storedsize option to return pixel data at stored resolution.
- Allow sequence and slice of scene indices in imread and asarray/asxarray.
- Interpret dimension slice selection as absolute coordinates.
- Fix CziImagePlanes not upsampling Airyscan fast-scan tiles.
- Fix CziImagePlanes not downsampling PALM super-resolution tiles.
- Add command line options to select dimensions.

2026.3.12

- Rewrite with many breaking changes.
- Support Zstd compression schemes.
- Support reading subblock masks.
- Add CziFile.scenes 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).

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:

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

Access scenes, shape, and metadata:

>>> 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:

>>> 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:

>>> import numpy
>>> 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 numpy.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:

>>> 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:

>>> 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:

>>> 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:

>>> 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:

>>> 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
