- no cloning if frame is owned already
PyTest / pytest (push) Successful in 1m26s
PyTest / pytest (3.10) (push) Successful in 1m48s
PyTest / pytest (3.12) (push) Successful in 1m59s
PyTest / pytest (3.14) (push) Successful in 2m6s

This commit is contained in:
Wim Pomp
2026-05-10 11:51:12 +02:00
parent 5a5bf9216f
commit 998b24e7af
4 changed files with 55 additions and 18 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "tiffwrite"
version = "2026.5.0"
version = "2026.5.1"
edition = "2024"
rust-version = "1.88.0"
authors = ["Wim Pomp <w.pomp@nki.nl>"]
+1 -1
View File
@@ -22,7 +22,7 @@ makes that very hard anyway.
or
- install [rust](https://rustup.rs/)
- ``` pip install tiffwrite@git+https://github.com/wimpomp/tiffwrite ```
- ``` pip install tiffwrite@git+https://git.wimpomp.nl/wim/tiffwrite ```
## Usage
### Write an image stack
-4
View File
@@ -29,10 +29,6 @@ dependencies = ["numpy", "tqdm"]
[project.optional-dependencies]
test = ["pytest", "tifffile", "imagecodecs"]
[project.urls]
homepage = "https://github.com/wimpomp/tiffwrite"
repository = "https://github.com/wimpomp/tiffwrite"
[project.scripts]
tiffwrite_generate_stub = "tiffwrite:tiffwrite_generate_stub"
+53 -12
View File
@@ -9,7 +9,7 @@ use colorgrad::{Gradient, LinearGradient};
use css_color::Srgb;
use flate2::write::ZlibEncoder;
use lazy_static::lazy_static;
use ndarray::{ArcArray2, AsArray, Ix2, s};
use ndarray::{Array, Array2, ArrayView, ArrayView2, Dimension, Ix2, s};
use num::{Complex, FromPrimitive, Rational32, traits::ToBytes};
use rayon::prelude::*;
use std::collections::HashSet;
@@ -380,7 +380,7 @@ impl Frame {
fn new<T>(
hashes: Arc<Mutex<HashMap<u64, u64>>>,
file: Arc<Mutex<BufWriter<File>>>,
frame: ArcArray2<T>,
frame: Array2<T>,
compression: Compression,
) -> Result<Frame, Error>
where
@@ -434,14 +434,14 @@ impl Frame {
slices
.into_par_iter()
.map(|slice| {
Frame::compress_tile_deflate(frame.clone(), slice, tile_size, tile_size)
Frame::compress_tile_deflate(frame.view(), slice, tile_size, tile_size)
})
.collect::<Result<Vec<_>, Error>>()?
} else {
slices
.into_iter()
.map(|slice| {
Frame::compress_tile_deflate(frame.clone(), slice, tile_size, tile_size)
Frame::compress_tile_deflate(frame.view(), slice, tile_size, tile_size)
})
.collect::<Result<Vec<_>, Error>>()?
}
@@ -453,7 +453,7 @@ impl Frame {
.into_par_iter()
.map(|slice| {
Frame::compress_tile_zstd(
frame.clone(),
frame.view(),
slice,
tile_size,
tile_size,
@@ -466,7 +466,7 @@ impl Frame {
.into_iter()
.map(|slice| {
Frame::compress_tile_zstd(
frame.clone(),
frame.view(),
slice,
tile_size,
tile_size,
@@ -501,7 +501,7 @@ impl Frame {
fn encode<W, T>(
mut encoder: W,
frame: ArcArray2<T>,
frame: ArrayView2<T>,
slice: (usize, usize, usize, usize),
tile_width: usize,
tile_length: usize,
@@ -532,7 +532,7 @@ impl Frame {
}
fn compress_tile_deflate<T>(
frame: ArcArray2<T>,
frame: ArrayView2<T>,
slice: (usize, usize, usize, usize),
tile_width: usize,
tile_length: usize,
@@ -546,7 +546,7 @@ impl Frame {
}
fn compress_tile_zstd<T>(
frame: ArcArray2<T>,
frame: ArrayView2<T>,
slice: (usize, usize, usize, usize),
tile_width: usize,
tile_length: usize,
@@ -621,6 +621,47 @@ pub enum Colors {
Colormap(Vec<Vec<u8>>),
}
/// Clone if array is a view, do not clone if array is owned already.
pub trait IntoOwnedArray<T, D> {
fn into_owned(self) -> Array<T, D>;
}
impl<T, D> IntoOwnedArray<T, D> for Array<T, D> {
fn into_owned(self) -> Array<T, D> {
self
}
}
impl<T, D> IntoOwnedArray<T, D> for &Array<T, D>
where
T: Clone,
D: Dimension,
{
fn into_owned(self) -> Array<T, D> {
self.to_owned()
}
}
impl<T, D> IntoOwnedArray<T, D> for ArrayView<'_, T, D>
where
T: Clone,
D: Dimension,
{
fn into_owned(self) -> Array<T, D> {
self.to_owned()
}
}
impl<T, D> IntoOwnedArray<T, D> for &ArrayView<'_, T, D>
where
T: Clone,
D: Dimension,
{
fn into_owned(self) -> Array<T, D> {
self.to_owned()
}
}
/// save 2d arrays in a tif file compatible with Fiji/ImageJ
#[derive(Debug)]
pub struct IJTiffFile {
@@ -842,15 +883,15 @@ impl IJTiffFile {
}
/// save a 2d array to the tiff file at channel c, slice z, and time t
pub fn save<'a, A, T>(&mut self, frame: A, c: usize, z: usize, t: usize) -> Result<(), Error>
pub fn save<A, T>(&mut self, frame: A, c: usize, z: usize, t: usize) -> Result<(), Error>
where
A: AsArray<'a, T, Ix2>,
A: IntoOwnedArray<T, Ix2>,
T: Bytes + Clone + Send + Sync + 'static,
{
self.collect_threads(false, usize::from(available_parallelism()?))?;
let hashes = self.hashes.clone();
let file = self.file.clone();
let frame = frame.into().to_shared();
let frame = frame.into_owned();
let compression = self.compression;
self.threads.insert(
(c, z, t),