- no cloning if frame is owned already
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tiffwrite"
|
name = "tiffwrite"
|
||||||
version = "2026.5.0"
|
version = "2026.5.1"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
rust-version = "1.88.0"
|
rust-version = "1.88.0"
|
||||||
authors = ["Wim Pomp <w.pomp@nki.nl>"]
|
authors = ["Wim Pomp <w.pomp@nki.nl>"]
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ makes that very hard anyway.
|
|||||||
or
|
or
|
||||||
|
|
||||||
- install [rust](https://rustup.rs/)
|
- 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
|
## Usage
|
||||||
### Write an image stack
|
### Write an image stack
|
||||||
|
|||||||
@@ -29,10 +29,6 @@ dependencies = ["numpy", "tqdm"]
|
|||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
test = ["pytest", "tifffile", "imagecodecs"]
|
test = ["pytest", "tifffile", "imagecodecs"]
|
||||||
|
|
||||||
[project.urls]
|
|
||||||
homepage = "https://github.com/wimpomp/tiffwrite"
|
|
||||||
repository = "https://github.com/wimpomp/tiffwrite"
|
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
tiffwrite_generate_stub = "tiffwrite:tiffwrite_generate_stub"
|
tiffwrite_generate_stub = "tiffwrite:tiffwrite_generate_stub"
|
||||||
|
|
||||||
|
|||||||
+53
-12
@@ -9,7 +9,7 @@ use colorgrad::{Gradient, LinearGradient};
|
|||||||
use css_color::Srgb;
|
use css_color::Srgb;
|
||||||
use flate2::write::ZlibEncoder;
|
use flate2::write::ZlibEncoder;
|
||||||
use lazy_static::lazy_static;
|
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 num::{Complex, FromPrimitive, Rational32, traits::ToBytes};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
@@ -380,7 +380,7 @@ impl Frame {
|
|||||||
fn new<T>(
|
fn new<T>(
|
||||||
hashes: Arc<Mutex<HashMap<u64, u64>>>,
|
hashes: Arc<Mutex<HashMap<u64, u64>>>,
|
||||||
file: Arc<Mutex<BufWriter<File>>>,
|
file: Arc<Mutex<BufWriter<File>>>,
|
||||||
frame: ArcArray2<T>,
|
frame: Array2<T>,
|
||||||
compression: Compression,
|
compression: Compression,
|
||||||
) -> Result<Frame, Error>
|
) -> Result<Frame, Error>
|
||||||
where
|
where
|
||||||
@@ -434,14 +434,14 @@ impl Frame {
|
|||||||
slices
|
slices
|
||||||
.into_par_iter()
|
.into_par_iter()
|
||||||
.map(|slice| {
|
.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>>()?
|
.collect::<Result<Vec<_>, Error>>()?
|
||||||
} else {
|
} else {
|
||||||
slices
|
slices
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|slice| {
|
.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>>()?
|
.collect::<Result<Vec<_>, Error>>()?
|
||||||
}
|
}
|
||||||
@@ -453,7 +453,7 @@ impl Frame {
|
|||||||
.into_par_iter()
|
.into_par_iter()
|
||||||
.map(|slice| {
|
.map(|slice| {
|
||||||
Frame::compress_tile_zstd(
|
Frame::compress_tile_zstd(
|
||||||
frame.clone(),
|
frame.view(),
|
||||||
slice,
|
slice,
|
||||||
tile_size,
|
tile_size,
|
||||||
tile_size,
|
tile_size,
|
||||||
@@ -466,7 +466,7 @@ impl Frame {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|slice| {
|
.map(|slice| {
|
||||||
Frame::compress_tile_zstd(
|
Frame::compress_tile_zstd(
|
||||||
frame.clone(),
|
frame.view(),
|
||||||
slice,
|
slice,
|
||||||
tile_size,
|
tile_size,
|
||||||
tile_size,
|
tile_size,
|
||||||
@@ -501,7 +501,7 @@ impl Frame {
|
|||||||
|
|
||||||
fn encode<W, T>(
|
fn encode<W, T>(
|
||||||
mut encoder: W,
|
mut encoder: W,
|
||||||
frame: ArcArray2<T>,
|
frame: ArrayView2<T>,
|
||||||
slice: (usize, usize, usize, usize),
|
slice: (usize, usize, usize, usize),
|
||||||
tile_width: usize,
|
tile_width: usize,
|
||||||
tile_length: usize,
|
tile_length: usize,
|
||||||
@@ -532,7 +532,7 @@ impl Frame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn compress_tile_deflate<T>(
|
fn compress_tile_deflate<T>(
|
||||||
frame: ArcArray2<T>,
|
frame: ArrayView2<T>,
|
||||||
slice: (usize, usize, usize, usize),
|
slice: (usize, usize, usize, usize),
|
||||||
tile_width: usize,
|
tile_width: usize,
|
||||||
tile_length: usize,
|
tile_length: usize,
|
||||||
@@ -546,7 +546,7 @@ impl Frame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn compress_tile_zstd<T>(
|
fn compress_tile_zstd<T>(
|
||||||
frame: ArcArray2<T>,
|
frame: ArrayView2<T>,
|
||||||
slice: (usize, usize, usize, usize),
|
slice: (usize, usize, usize, usize),
|
||||||
tile_width: usize,
|
tile_width: usize,
|
||||||
tile_length: usize,
|
tile_length: usize,
|
||||||
@@ -621,6 +621,47 @@ pub enum Colors {
|
|||||||
Colormap(Vec<Vec<u8>>),
|
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
|
/// save 2d arrays in a tif file compatible with Fiji/ImageJ
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct IJTiffFile {
|
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
|
/// 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
|
where
|
||||||
A: AsArray<'a, T, Ix2>,
|
A: IntoOwnedArray<T, Ix2>,
|
||||||
T: Bytes + Clone + Send + Sync + 'static,
|
T: Bytes + Clone + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
self.collect_threads(false, usize::from(available_parallelism()?))?;
|
self.collect_threads(false, usize::from(available_parallelism()?))?;
|
||||||
let hashes = self.hashes.clone();
|
let hashes = self.hashes.clone();
|
||||||
let file = self.file.clone();
|
let file = self.file.clone();
|
||||||
let frame = frame.into().to_shared();
|
let frame = frame.into_owned();
|
||||||
let compression = self.compression;
|
let compression = self.compression;
|
||||||
self.threads.insert(
|
self.threads.insert(
|
||||||
(c, z, t),
|
(c, z, t),
|
||||||
|
|||||||
Reference in New Issue
Block a user