[](https://github.com/wimpomp/tiffwrite/actions/workflows/pytest.yml)
# Tiffwrite
Write BioFormats/ImageJ compatible tiffs with zstd compression in parallel using Rust.
## Features
- Writes bigtiff files that open in ImageJ as hyperstack with correct dimensions.
- Parallel compression.
- Write individual frames in random order.
- Compresses even more by referencing tag or image data which otherwise would have been saved several times.
For example empty frames, or a long string tag on every frame. Editing tiffs becomes mostly impossible, but compression
makes that very hard anyway.
- Enables memory efficient scripts by saving frames whenever they're ready to be saved, not waiting for the whole stack.
- Colormaps
- Extra tags, globally or frame dependent.
# Python
## Installation
```pip install tiffwrite```
or
- install [rust](https://rustup.rs/)
- ``` pip install tiffwrite@git+https://github.com/wimpomp/tiffwrite ```
## Usage
### Write an image stack
tiffwrite(file, data, axes='TZCXY', dtype=None, bar=False, *args, **kwargs)
- file: string; filename of the new tiff file.
- data: 2 to 5D numpy array in one of these datatypes: (u)int8, (u)int16, float32.
- axes: string; order of dimensions in data, default: TZCXY for 5D, ZCXY for 4D, CXY for 3D, XY for 2D data.
- dtype: string; cast data to dtype before saving, only (u)int8, (u)int16 and float32 are supported.
- bar: bool; whether to show a progress bar.
- args, kwargs: arguments to be passed to IJTiffFile, see below.
### Write one frame at a time
with IJTiffFile(file, dtype='uint16', colors=None, colormap=None, pxsize=None, deltaz=None,
timeinterval=None, **extratags) as tif:
some loop:
tif.save(frame, c, z, t)
- path: string; path to the new tiff file.
- dtype: string; cast data to dtype before saving, only (u)int8, (u)int16 and float32 are supported by Fiji.
- colors: iterable of strings; one color per channel, valid colors (also html) are defined in matplotlib.colors.
Without colormap BioFormats will set the colors in this order: rgbwcmy.
Note that the color green is dark, the usual green is named 'lime' here.
- colormap: string; choose any colormap from the colorcet module. Colors and colormap cannot be used simultaneously.
- pxsize: float; pixel size im um.
- deltaz: float; z slice interval in um.
- timeinterval: float; time between frames in seconds.
- compression: int; zstd compression level: -7 to 22.
- comment: str; comment to be saved in tif
- extratags: Sequence\[Tag\]; other tags to be saved, example: Tag.ascii(315, 'John Doe') or Tag.ascii(33432, 'Made by me').
- frame: 2D numpy array with data.
- c, z, t: int; channel, z, time coordinates of the frame.
## Examples
### Write an image stack
from tiffwrite import tiffwrite
import numpy as np
image = np.random.randint(0, 255, (5, 3, 64, 64), 'uint16')
tiffwrite('file.tif', image, 'TCXY')
### Write one frame at a time
from tiffwrite import IJTiffFile
import numpy as np
with IJTiffFile('file.tif', pxsize=0.09707) as tif:
for c in range(3):
for z in range(5):
for t in range(10):
tif.save(np.random.randint(0, 10, (32, 32)), c, z, t)
### Saving multiple tiffs simultaneously
from tiffwrite import IJTiffFile
import numpy as np
with IJTiffFile('fileA.tif') as tif_a, IJTiffFile('fileB.tif') as tif_b:
for c in range(3):
for z in range(5):
for t in range(10):
tif_a.save(np.random.randint(0, 10, (32, 32)), c, z, t)
tif_b.save(np.random.randint(0, 10, (32, 32)), c, z, t)
# Rust
use ndarray::Array2;
use tiffwrite::IJTiffFile;
{ // f will be closed when f goes out of scope
let mut f = IJTiffFile::new("file.tif")?;
for c in 0..3 {
for z in 0..5 {
for t in 0..10 {
let arr = Array2::<u16>::zeros((100, 100));
f.save(&arr, c, z, t)?;
}
}
}
}
# Tricks & tips
- The order of feeding frames to IJTiffFile is unimportant, IJTiffFile will order the ifd's such that the file will be opened as a correctly ordered hyperstack.
- Using the colormap parameter you can make ImageJ open the file and apply the colormap. colormap='glasbey' is very useful.
Raw data
{
"_id": null,
"home_page": "https://github.com/wimpomp/tiffwrite",
"name": "tiffwrite",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.10",
"maintainer_email": null,
"keywords": "bioformats, tiff, ndarray, zstd, fiji",
"author": null,
"author_email": "Wim Pomp <w.pomp@nki.nl>",
"download_url": "https://files.pythonhosted.org/packages/53/90/8b3df062bd3941211493aad2a563dec703857b00129291835599a08700cf/tiffwrite-2025.8.1.tar.gz",
"platform": null,
"description": "[](https://github.com/wimpomp/tiffwrite/actions/workflows/pytest.yml)\n\n# Tiffwrite\nWrite BioFormats/ImageJ compatible tiffs with zstd compression in parallel using Rust.\n\n## Features\n- Writes bigtiff files that open in ImageJ as hyperstack with correct dimensions.\n- Parallel compression.\n- Write individual frames in random order.\n- Compresses even more by referencing tag or image data which otherwise would have been saved several times.\nFor example empty frames, or a long string tag on every frame. Editing tiffs becomes mostly impossible, but compression\nmakes that very hard anyway.\n- Enables memory efficient scripts by saving frames whenever they're ready to be saved, not waiting for the whole stack.\n- Colormaps\n- Extra tags, globally or frame dependent.\n\n# Python\n## Installation\n```pip install tiffwrite```\n\nor\n\n- install [rust](https://rustup.rs/)\n- ``` pip install tiffwrite@git+https://github.com/wimpomp/tiffwrite ```\n\n## Usage\n### Write an image stack\n tiffwrite(file, data, axes='TZCXY', dtype=None, bar=False, *args, **kwargs)\n\n- file: string; filename of the new tiff file.\n- data: 2 to 5D numpy array in one of these datatypes: (u)int8, (u)int16, float32.\n- axes: string; order of dimensions in data, default: TZCXY for 5D, ZCXY for 4D, CXY for 3D, XY for 2D data.\n- dtype: string; cast data to dtype before saving, only (u)int8, (u)int16 and float32 are supported.\n- bar: bool; whether to show a progress bar.\n- args, kwargs: arguments to be passed to IJTiffFile, see below.\n\n\n### Write one frame at a time\n with IJTiffFile(file, dtype='uint16', colors=None, colormap=None, pxsize=None, deltaz=None,\n timeinterval=None, **extratags) as tif:\n some loop:\n tif.save(frame, c, z, t)\n\n- path: string; path to the new tiff file.\n- dtype: string; cast data to dtype before saving, only (u)int8, (u)int16 and float32 are supported by Fiji.\n- colors: iterable of strings; one color per channel, valid colors (also html) are defined in matplotlib.colors.\n Without colormap BioFormats will set the colors in this order: rgbwcmy.\n Note that the color green is dark, the usual green is named 'lime' here.\n- colormap: string; choose any colormap from the colorcet module. Colors and colormap cannot be used simultaneously.\n- pxsize: float; pixel size im um.\n- deltaz: float; z slice interval in um.\n- timeinterval: float; time between frames in seconds.\n- compression: int; zstd compression level: -7 to 22.\n- comment: str; comment to be saved in tif\n- extratags: Sequence\\[Tag\\]; other tags to be saved, example: Tag.ascii(315, 'John Doe') or Tag.ascii(33432, 'Made by me').\n\n\n- frame: 2D numpy array with data.\n- c, z, t: int; channel, z, time coordinates of the frame.\n\n \n## Examples\n### Write an image stack\n from tiffwrite import tiffwrite\n import numpy as np\n\n image = np.random.randint(0, 255, (5, 3, 64, 64), 'uint16')\n tiffwrite('file.tif', image, 'TCXY')\n\n### Write one frame at a time\n from tiffwrite import IJTiffFile\n import numpy as np\n\n with IJTiffFile('file.tif', pxsize=0.09707) as tif:\n for c in range(3):\n for z in range(5):\n for t in range(10):\n tif.save(np.random.randint(0, 10, (32, 32)), c, z, t)\n\n### Saving multiple tiffs simultaneously\n from tiffwrite import IJTiffFile\n import numpy as np\n\n with IJTiffFile('fileA.tif') as tif_a, IJTiffFile('fileB.tif') as tif_b:\n for c in range(3):\n for z in range(5):\n for t in range(10):\n tif_a.save(np.random.randint(0, 10, (32, 32)), c, z, t)\n tif_b.save(np.random.randint(0, 10, (32, 32)), c, z, t)\n\n\n# Rust\n use ndarray::Array2;\n use tiffwrite::IJTiffFile;\n\n { // f will be closed when f goes out of scope\n let mut f = IJTiffFile::new(\"file.tif\")?;\n for c in 0..3 {\n for z in 0..5 {\n for t in 0..10 {\n let arr = Array2::<u16>::zeros((100, 100));\n f.save(&arr, c, z, t)?;\n }\n }\n }\n }\n\n# Tricks & tips\n- The order of feeding frames to IJTiffFile is unimportant, IJTiffFile will order the ifd's such that the file will be opened as a correctly ordered hyperstack.\n- Using the colormap parameter you can make ImageJ open the file and apply the colormap. colormap='glasbey' is very useful.\n\n",
"bugtrack_url": null,
"license": null,
"summary": "Write BioFormats/ImageJ compatible tiffs with zstd compression in parallel.",
"version": "2025.8.1",
"project_urls": {
"Homepage": "https://github.com/wimpomp/tiffwrite",
"repository": "https://github.com/wimpomp/tiffwrite"
},
"split_keywords": [
"bioformats",
" tiff",
" ndarray",
" zstd",
" fiji"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "9032052ff7f44ed59ada165dd025b989a3857d12583067c0014783f7fe7ed00e",
"md5": "31f244ddbe739dbbe233d50e4b1604c1",
"sha256": "d62595df051034444c179c9d57e6585c4d16334e0327c20eb8c23589a45d6369"
},
"downloads": -1,
"filename": "tiffwrite-2025.8.1-cp310-abi3-macosx_10_12_x86_64.whl",
"has_sig": false,
"md5_digest": "31f244ddbe739dbbe233d50e4b1604c1",
"packagetype": "bdist_wheel",
"python_version": "cp310",
"requires_python": ">=3.10",
"size": 1433353,
"upload_time": "2025-08-23T21:18:19",
"upload_time_iso_8601": "2025-08-23T21:18:19.175015Z",
"url": "https://files.pythonhosted.org/packages/90/32/052ff7f44ed59ada165dd025b989a3857d12583067c0014783f7fe7ed00e/tiffwrite-2025.8.1-cp310-abi3-macosx_10_12_x86_64.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "a5132227c472b6a7c4d325c983816f28d42c1621282d0d6a0ca18de8dbf641ab",
"md5": "58bbf0510674aed112abc890d565fe81",
"sha256": "308c3d3516aae99d6a1fd2992823db1d4e644e90249b4db9f03348db41e5ebaa"
},
"downloads": -1,
"filename": "tiffwrite-2025.8.1-cp310-abi3-macosx_11_0_arm64.whl",
"has_sig": false,
"md5_digest": "58bbf0510674aed112abc890d565fe81",
"packagetype": "bdist_wheel",
"python_version": "cp310",
"requires_python": ">=3.10",
"size": 1383522,
"upload_time": "2025-08-23T21:18:17",
"upload_time_iso_8601": "2025-08-23T21:18:17.720573Z",
"url": "https://files.pythonhosted.org/packages/a5/13/2227c472b6a7c4d325c983816f28d42c1621282d0d6a0ca18de8dbf641ab/tiffwrite-2025.8.1-cp310-abi3-macosx_11_0_arm64.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "6afaef30006ed45a27a55dd08cc82cc6179b08ffec5edaff67a51b3a32099472",
"md5": "0df6e3830b30a331ad5213dfc6c8dd95",
"sha256": "2e6dc3fae2127c47f9a32b52ed7512ffc8d48d44b254c29a24a39fb103c9dc9e"
},
"downloads": -1,
"filename": "tiffwrite-2025.8.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl",
"has_sig": false,
"md5_digest": "0df6e3830b30a331ad5213dfc6c8dd95",
"packagetype": "bdist_wheel",
"python_version": "cp310",
"requires_python": ">=3.10",
"size": 1509207,
"upload_time": "2025-08-23T21:18:08",
"upload_time_iso_8601": "2025-08-23T21:18:08.330438Z",
"url": "https://files.pythonhosted.org/packages/6a/fa/ef30006ed45a27a55dd08cc82cc6179b08ffec5edaff67a51b3a32099472/tiffwrite-2025.8.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "a9d60c04f097e3dec60965913937b4593e0c3d47210e457ebd5da5c4d7eae91e",
"md5": "4e22c8baa347baba67d7b6773e0ed424",
"sha256": "9da413455468c82be03847eccefcc30acd9963f8a7d6953668d601987ca040fd"
},
"downloads": -1,
"filename": "tiffwrite-2025.8.1-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl",
"has_sig": false,
"md5_digest": "4e22c8baa347baba67d7b6773e0ed424",
"packagetype": "bdist_wheel",
"python_version": "cp310",
"requires_python": ">=3.10",
"size": 1529265,
"upload_time": "2025-08-23T21:18:10",
"upload_time_iso_8601": "2025-08-23T21:18:10.085569Z",
"url": "https://files.pythonhosted.org/packages/a9/d6/0c04f097e3dec60965913937b4593e0c3d47210e457ebd5da5c4d7eae91e/tiffwrite-2025.8.1-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "c6dd09390104dc373c83b148bf577b552c99680e6a2d3b1648d9bf49d7a535d5",
"md5": "ecf909c9b04b94e967c7c30b09ab7657",
"sha256": "eff08e052d68d43eaae1087dcd3e4d4979a422bf429be8fbadfcb747bebe64ec"
},
"downloads": -1,
"filename": "tiffwrite-2025.8.1-cp310-abi3-manylinux_2_17_i686.manylinux2014_i686.whl",
"has_sig": false,
"md5_digest": "ecf909c9b04b94e967c7c30b09ab7657",
"packagetype": "bdist_wheel",
"python_version": "cp310",
"requires_python": ">=3.10",
"size": 1555338,
"upload_time": "2025-08-23T21:18:14",
"upload_time_iso_8601": "2025-08-23T21:18:14.569196Z",
"url": "https://files.pythonhosted.org/packages/c6/dd/09390104dc373c83b148bf577b552c99680e6a2d3b1648d9bf49d7a535d5/tiffwrite-2025.8.1-cp310-abi3-manylinux_2_17_i686.manylinux2014_i686.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "9f27f236f2dc93e6cc83ae9d43e57c189636652ba2fadae4e4ec87a11e2c7dc9",
"md5": "77636f3854eb88d8ba0fdf153399ced5",
"sha256": "4b370e04cc98862731388fb1b435d5da88db89e5f86c7e6d9b3a668603ce531c"
},
"downloads": -1,
"filename": "tiffwrite-2025.8.1-cp310-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
"has_sig": false,
"md5_digest": "77636f3854eb88d8ba0fdf153399ced5",
"packagetype": "bdist_wheel",
"python_version": "cp310",
"requires_python": ">=3.10",
"size": 1665354,
"upload_time": "2025-08-23T21:18:11",
"upload_time_iso_8601": "2025-08-23T21:18:11.613045Z",
"url": "https://files.pythonhosted.org/packages/9f/27/f236f2dc93e6cc83ae9d43e57c189636652ba2fadae4e4ec87a11e2c7dc9/tiffwrite-2025.8.1-cp310-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "b528919977f5c83d77d9130f65b0793b507dadb43dfe1d5ac51052377d861ef5",
"md5": "849885852ee5f692c2aa684d03170e2a",
"sha256": "f3131408c02fbfc8976ae92d24888b6ad84b2e6f49fdd2bafb0e51ce1614ef4d"
},
"downloads": -1,
"filename": "tiffwrite-2025.8.1-cp310-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl",
"has_sig": false,
"md5_digest": "849885852ee5f692c2aa684d03170e2a",
"packagetype": "bdist_wheel",
"python_version": "cp310",
"requires_python": ">=3.10",
"size": 1590433,
"upload_time": "2025-08-23T21:18:13",
"upload_time_iso_8601": "2025-08-23T21:18:13.090732Z",
"url": "https://files.pythonhosted.org/packages/b5/28/919977f5c83d77d9130f65b0793b507dadb43dfe1d5ac51052377d861ef5/tiffwrite-2025.8.1-cp310-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "386dc226676197332db9d4d4536ff55e9d7dd123db59493c1a52deaf0d4e58e7",
"md5": "2267a7502c3eed9af12e50ac5f6fa0c4",
"sha256": "24c1f1bfc53d2b827fd1cd15d7b0438604ec40f10993899dbdad9a53c3690de7"
},
"downloads": -1,
"filename": "tiffwrite-2025.8.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
"has_sig": false,
"md5_digest": "2267a7502c3eed9af12e50ac5f6fa0c4",
"packagetype": "bdist_wheel",
"python_version": "cp310",
"requires_python": ">=3.10",
"size": 1520735,
"upload_time": "2025-08-23T21:18:16",
"upload_time_iso_8601": "2025-08-23T21:18:16.179010Z",
"url": "https://files.pythonhosted.org/packages/38/6d/c226676197332db9d4d4536ff55e9d7dd123db59493c1a52deaf0d4e58e7/tiffwrite-2025.8.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "5cc39170ca86ac80437a12cf8829ea258df80e356e116ba7dcbdc5b227615df1",
"md5": "883daf9063084d800e38334f1b872d62",
"sha256": "f0769edfbce75b5ec8f9fb63014bf956e1935c79252a2231b46b39e49d47440d"
},
"downloads": -1,
"filename": "tiffwrite-2025.8.1-cp310-abi3-win_amd64.whl",
"has_sig": false,
"md5_digest": "883daf9063084d800e38334f1b872d62",
"packagetype": "bdist_wheel",
"python_version": "cp310",
"requires_python": ">=3.10",
"size": 1239339,
"upload_time": "2025-08-23T21:18:21",
"upload_time_iso_8601": "2025-08-23T21:18:21.085535Z",
"url": "https://files.pythonhosted.org/packages/5c/c3/9170ca86ac80437a12cf8829ea258df80e356e116ba7dcbdc5b227615df1/tiffwrite-2025.8.1-cp310-abi3-win_amd64.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "53908b3df062bd3941211493aad2a563dec703857b00129291835599a08700cf",
"md5": "0ee08bf5eaec6990b3e0d96f47680879",
"sha256": "c8fd005ba12d2310cfa4b05d06dcb3273fb0eb85750d7301711eba0a247d4231"
},
"downloads": -1,
"filename": "tiffwrite-2025.8.1.tar.gz",
"has_sig": false,
"md5_digest": "0ee08bf5eaec6990b3e0d96f47680879",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10",
"size": 25948,
"upload_time": "2025-08-23T21:18:20",
"upload_time_iso_8601": "2025-08-23T21:18:20.372811Z",
"url": "https://files.pythonhosted.org/packages/53/90/8b3df062bd3941211493aad2a563dec703857b00129291835599a08700cf/tiffwrite-2025.8.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-23 21:18:20",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "wimpomp",
"github_project": "tiffwrite",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "tiffwrite"
}