- python: remove deprecated shape argument
- rust: make frame argument to save more generic
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
name: Wheels
|
name: Publish
|
||||||
|
|
||||||
on: [push, pull_request, workflow_call]
|
on: [push, pull_request, workflow_call]
|
||||||
|
|
||||||
@@ -6,10 +6,10 @@ permissions:
|
|||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
wheels_pytest:
|
publish_pytest:
|
||||||
uses: ./.github/workflows/pytest.yml
|
uses: ./.github/workflows/pytest.yml
|
||||||
linux:
|
linux:
|
||||||
needs: [ wheels_pytest ]
|
needs: [ publish_pytest ]
|
||||||
runs-on: ${{ matrix.platform.runner }}
|
runs-on: ${{ matrix.platform.runner }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
@@ -45,7 +45,7 @@ jobs:
|
|||||||
path: dist
|
path: dist
|
||||||
|
|
||||||
windows:
|
windows:
|
||||||
needs: [ wheels_pytest ]
|
needs: [ publish_pytest ]
|
||||||
runs-on: ${{ matrix.platform.runner }}
|
runs-on: ${{ matrix.platform.runner }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
@@ -73,7 +73,7 @@ jobs:
|
|||||||
path: dist
|
path: dist
|
||||||
|
|
||||||
macos:
|
macos:
|
||||||
needs: [ wheels_pytest ]
|
needs: [ publish_pytest ]
|
||||||
runs-on: ${{ matrix.platform.runner }}
|
runs-on: ${{ matrix.platform.runner }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
@@ -100,7 +100,7 @@ jobs:
|
|||||||
path: dist
|
path: dist
|
||||||
|
|
||||||
sdist:
|
sdist:
|
||||||
needs: [ wheels_pytest ]
|
needs: [ publish_pytest ]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -128,3 +128,51 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
command: upload
|
command: upload
|
||||||
args: --non-interactive --skip-existing wheels-*/*
|
args: --non-interactive --skip-existing wheels-*/*
|
||||||
|
|
||||||
|
crates_io_publish:
|
||||||
|
name: Publish (crates.io)
|
||||||
|
needs: [ publish_pytest ]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 25
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
|
||||||
|
- name: cargo-release Cache
|
||||||
|
id: cargo_release_cache
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: ~/.cargo/bin/cargo-release
|
||||||
|
key: ${{ runner.os }}-cargo-release
|
||||||
|
|
||||||
|
- run: cargo install cargo-release
|
||||||
|
if: steps.cargo_release_cache.outputs.cache-hit != 'true'
|
||||||
|
|
||||||
|
- name: cargo login
|
||||||
|
run: cargo login ${{ secrets.CRATES_IO_API_TOKEN }}
|
||||||
|
|
||||||
|
# allow-branch HEAD is because GitHub actions switches
|
||||||
|
# to the tag while building, which is a detached head
|
||||||
|
|
||||||
|
# Publishing is currently messy, because:
|
||||||
|
#
|
||||||
|
# * `peace_rt_model_core` exports `NativeError` or `WebError` depending on the target.
|
||||||
|
# * `peace_rt_model_web` fails to build when publishing the workspace for a native target.
|
||||||
|
# * `peace_rt_model_web` still needs its dependencies to be published before it can be
|
||||||
|
# published.
|
||||||
|
# * `peace_rt_model_hack` needs `peace_rt_model_web` to be published before it can be
|
||||||
|
# published.
|
||||||
|
#
|
||||||
|
# We *could* pass through `--no-verify` so `cargo` doesn't build the crate before publishing,
|
||||||
|
# which is reasonable, since this job only runs after the Linux, Windows, and WASM builds
|
||||||
|
# have passed.
|
||||||
|
- name: "cargo release publish"
|
||||||
|
run: |-
|
||||||
|
cargo release \
|
||||||
|
publish \
|
||||||
|
--workspace \
|
||||||
|
--all-features \
|
||||||
|
--allow-branch HEAD \
|
||||||
|
--no-confirm \
|
||||||
|
--no-verify \
|
||||||
|
--execute
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tiffwrite"
|
name = "tiffwrite"
|
||||||
version = "2024.10.7"
|
version = "2024.10.8"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = ["Wim Pomp <w.pomp@nki.nl>"]
|
authors = ["Wim Pomp <w.pomp@nki.nl>"]
|
||||||
license = "GPL-3.0-or-later"
|
license = "GPL-3.0-or-later"
|
||||||
|
|||||||
69
README.md
69
README.md
@@ -14,36 +14,35 @@ makes that very hard anyway.
|
|||||||
- Colormaps
|
- Colormaps
|
||||||
- Extra tags, globally or frame dependent.
|
- Extra tags, globally or frame dependent.
|
||||||
|
|
||||||
|
# Python
|
||||||
## Installation
|
## Installation
|
||||||
pip install tiffwrite
|
```pip install tiffwrite```
|
||||||
|
|
||||||
or
|
or
|
||||||
|
|
||||||
- install [rust](https://rustup.rs/)
|
- install [rust](https://rustup.rs/)
|
||||||
|
- ``` pip install tiffwrite@git+https://github.com/wimpomp/tiffwrite ```
|
||||||
|
|
||||||
|
## Usage
|
||||||
pip install tiffwrite@git+https://github.com/wimpomp/tiffwrite
|
### Write an image stack
|
||||||
|
|
||||||
# Usage
|
|
||||||
## Write an image stack
|
|
||||||
tiffwrite(file, data, axes='TZCXY', dtype=None, bar=False, *args, **kwargs)
|
tiffwrite(file, data, axes='TZCXY', dtype=None, bar=False, *args, **kwargs)
|
||||||
|
|
||||||
- file: string; filename of the new tiff file.
|
- file: string; filename of the new tiff file.
|
||||||
- data: 2 to 5D numpy array in one of these datatypes: (u)int8, (u)int16, float32.
|
- 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.
|
- 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.
|
- dtype: string; cast data to dtype before saving, only (u)int8, (u)int16 and float32 are supported.
|
||||||
- bar: bool; whether or not to show a progress bar.
|
- bar: bool; whether to show a progress bar.
|
||||||
- args, kwargs: arguments to be passed to IJTiffFile, see below.
|
- args, kwargs: arguments to be passed to IJTiffFile, see below.
|
||||||
|
|
||||||
|
|
||||||
## Write one frame at a time
|
### Write one frame at a time
|
||||||
with IJTiffFile(file, shape, dtype='uint16', colors=None, colormap=None, pxsize=None, deltaz=None,
|
with IJTiffFile(file, dtype='uint16', colors=None, colormap=None, pxsize=None, deltaz=None,
|
||||||
timeinterval=None, **extratags) as tif:
|
timeinterval=None, **extratags) as tif:
|
||||||
some loop:
|
some loop:
|
||||||
tif.save(frame, c, z, t)
|
tif.save(frame, c, z, t)
|
||||||
|
|
||||||
- file: string; filename of the new tiff file.
|
- path: string; path to the new tiff file.
|
||||||
- shape: iterable; shape (C, Z, T) of data to be written in file.
|
- dtype: string; cast data to dtype before saving, only (u)int8, (u)int16 and float32 are supported by Fiji.
|
||||||
- dtype: string; cast data to dtype before saving, only (u)int8, (u)int16 and float32 are supported.
|
|
||||||
- colors: iterable of strings; one color per channel, valid colors (also html) are defined in matplotlib.colors.
|
- 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.
|
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.
|
Note that the color green is dark, the usual green is named 'lime' here.
|
||||||
@@ -51,22 +50,24 @@ or
|
|||||||
- pxsize: float; pixel size im um.
|
- pxsize: float; pixel size im um.
|
||||||
- deltaz: float; z slice interval in um.
|
- deltaz: float; z slice interval in um.
|
||||||
- timeinterval: float; time between frames in seconds.
|
- timeinterval: float; time between frames in seconds.
|
||||||
- extratags: other tags to be saved, example: Artist='John Doe', Tag4567=[400, 500] or
|
- compression: int; zstd compression level: -7 to 22.
|
||||||
Copyright=Tag('ascii', 'Made by me'). See tiff_tag_registry.items().
|
- 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.
|
- frame: 2D numpy array with data.
|
||||||
- c, z, t: int; channel, z, time coordinates of the frame.
|
- c, z, t: int; channel, z, time coordinates of the frame.
|
||||||
|
|
||||||
|
|
||||||
# Examples
|
## Examples
|
||||||
## Write an image stack
|
### Write an image stack
|
||||||
from tiffwrite import tiffwrite
|
from tiffwrite import tiffwrite
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
image = np.random.randint(0, 255, (5, 3, 64, 64), 'uint16')
|
image = np.random.randint(0, 255, (5, 3, 64, 64), 'uint16')
|
||||||
tiffwrite('file.tif', image, 'TCXY')
|
tiffwrite('file.tif', image, 'TCXY')
|
||||||
|
|
||||||
## Write one frame at a time
|
### Write one frame at a time
|
||||||
from tiffwrite import IJTiffFile
|
from tiffwrite import IJTiffFile
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
@@ -76,20 +77,34 @@ or
|
|||||||
for t in range(10):
|
for t in range(10):
|
||||||
tif.save(np.random.randint(0, 10, (32, 32)), c, z, t)
|
tif.save(np.random.randint(0, 10, (32, 32)), c, z, t)
|
||||||
|
|
||||||
## Saving multiple tiffs simultaneously
|
### Saving multiple tiffs simultaneously
|
||||||
from tiffwrite import IJTiffFile
|
from tiffwrite import IJTiffFile
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
shape = (3, 5, 10) # channels, z, time
|
|
||||||
with IJTiffFile('fileA.tif') as tif_a, IJTiffFile('fileB.tif') as tif_b:
|
with IJTiffFile('fileA.tif') as tif_a, IJTiffFile('fileB.tif') as tif_b:
|
||||||
for c in range(shape[0]):
|
for c in range(3):
|
||||||
for z in range(shape[1]):
|
for z in range(5):
|
||||||
for t in range(shape[2]):
|
for t in range(10):
|
||||||
tif_a.save(np.random.randint(0, 10, (32, 32)), c, z, t)
|
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)
|
tif_b.save(np.random.randint(0, 10, (32, 32)), 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
|
# Rust
|
||||||
be opened as a correctly ordered hyperstack.
|
use ndarray::Array2;
|
||||||
- Using the colormap parameter you can make ImageJ open the file and apply the colormap. colormap='glasbey' is very
|
use tiffwrite::IJTiffFile;
|
||||||
useful.
|
|
||||||
|
{ // 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.
|
||||||
|
|||||||
@@ -36,26 +36,26 @@ class TiffWriteWarning(UserWarning):
|
|||||||
class IJTiffFile(rs.IJTiffFile):
|
class IJTiffFile(rs.IJTiffFile):
|
||||||
""" Writes a tiff file in a format that the BioFormats reader in Fiji understands.
|
""" Writes a tiff file in a format that the BioFormats reader in Fiji understands.
|
||||||
Zstd compression is done in parallel using Rust.
|
Zstd compression is done in parallel using Rust.
|
||||||
file: filename of the new tiff file
|
path: path to the new tiff file
|
||||||
shape: not used anymore
|
|
||||||
dtype: datatype to use when saving to tiff
|
dtype: datatype to use when saving to tiff
|
||||||
colors: a tuple with a color per channel, chosen from matplotlib.colors, html colors are also possible
|
colors: a tuple with a color per channel, chosen from matplotlib.colors, html colors are also possible
|
||||||
colormap: name of a colormap from colorcet
|
colormap: name of a colormap from colorcet
|
||||||
pxsize: pixel size in um
|
pxsize: pixel size in um
|
||||||
deltaz: z slice interval in um
|
deltaz: z slice interval in um
|
||||||
timeinterval: time between frames in seconds
|
timeinterval: time between frames in seconds
|
||||||
|
compression: zstd compression level: -7 to 22.
|
||||||
|
comment: comment to be saved in tif
|
||||||
extratags: other tags to be saved, example: (Tag.ascii(315, 'John Doe'), Tag.bytes(4567, [400, 500])
|
extratags: other tags to be saved, example: (Tag.ascii(315, 'John Doe'), Tag.bytes(4567, [400, 500])
|
||||||
or (Tag.ascii(33432, 'Made by me'),).
|
or (Tag.ascii(33432, 'Made by me'),).
|
||||||
"""
|
"""
|
||||||
def __new__(cls, path: str | Path, *args, **kwargs) -> IJTiffFile:
|
def __new__(cls, path: str | Path, *args, **kwargs) -> IJTiffFile:
|
||||||
return super().__new__(cls, str(path))
|
return super().__new__(cls, str(path))
|
||||||
|
|
||||||
def __init__(self, path: str | Path, shape: tuple[int, int, int] = None, dtype: DTypeLike = 'uint16',
|
def __init__(self, path: str | Path, *, dtype: DTypeLike = 'uint16',
|
||||||
colors: Sequence[str] = None, colormap: str = None, pxsize: float = None,
|
colors: Sequence[str] = None, colormap: str = None, pxsize: float = None,
|
||||||
deltaz: float = None, timeinterval: float = None, compression: int = None, comment: str = None,
|
deltaz: float = None, timeinterval: float = None, compression: int = None, comment: str = None,
|
||||||
extratags: Sequence[Tag] = None) -> None:
|
extratags: Sequence[Tag] = None) -> None:
|
||||||
self.path = Path(path)
|
self.path = Path(path)
|
||||||
self.shape = shape
|
|
||||||
self.dtype = np.dtype(dtype)
|
self.dtype = np.dtype(dtype)
|
||||||
if compression is not None:
|
if compression is not None:
|
||||||
if isinstance(compression, Sequence):
|
if isinstance(compression, Sequence):
|
||||||
@@ -79,9 +79,6 @@ class IJTiffFile(rs.IJTiffFile):
|
|||||||
if self.dtype.itemsize == 1 and colors is not None:
|
if self.dtype.itemsize == 1 and colors is not None:
|
||||||
warn('Fiji will not interpret colors saved in an (u)int8 tif, save as (u)int16 instead.',
|
warn('Fiji will not interpret colors saved in an (u)int8 tif, save as (u)int16 instead.',
|
||||||
TiffWriteWarning, stacklevel=2)
|
TiffWriteWarning, stacklevel=2)
|
||||||
if shape is not None:
|
|
||||||
warn('Providing shape is not needed anymore, the argument will be removed in the future.',
|
|
||||||
DeprecationWarning, stacklevel=2)
|
|
||||||
if colors is not None and colormap is not None:
|
if colors is not None and colormap is not None:
|
||||||
warn('Cannot have colors and colormap simultaneously.', TiffWriteWarning, stacklevel=2)
|
warn('Cannot have colors and colormap simultaneously.', TiffWriteWarning, stacklevel=2)
|
||||||
|
|
||||||
@@ -176,7 +173,7 @@ def tiffwrite(file: str | Path, data: np.ndarray, axes: str = 'TZCXY', dtype: DT
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
from parfor import ParPool, Task
|
from parfor import ParPool, Task
|
||||||
from abc import abstractmethod, ABCMeta
|
from abc import ABCMeta, abstractmethod
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
44
src/lib.rs
44
src/lib.rs
@@ -3,7 +3,7 @@ mod py;
|
|||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use ndarray::{s, Array2, ArrayView2};
|
use ndarray::{s, ArcArray2, Array2, ArrayView2, AsArray, Ix2};
|
||||||
use num::{traits::ToBytes, Complex, FromPrimitive, Rational32, Zero};
|
use num::{traits::ToBytes, Complex, FromPrimitive, Rational32, Zero};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
@@ -148,7 +148,8 @@ impl Tag {
|
|||||||
pub fn long(code: u16, value: &Vec<u32>) -> Self {
|
pub fn long(code: u16, value: &Vec<u32>) -> Self {
|
||||||
Tag::new(
|
Tag::new(
|
||||||
code,
|
code,
|
||||||
value.into_iter()
|
value
|
||||||
|
.into_iter()
|
||||||
.map(|x| x.to_le_bytes())
|
.map(|x| x.to_le_bytes())
|
||||||
.flatten()
|
.flatten()
|
||||||
.collect(),
|
.collect(),
|
||||||
@@ -253,7 +254,11 @@ impl Tag {
|
|||||||
pub fn ifd(code: u16, value: &Vec<u32>) -> Self {
|
pub fn ifd(code: u16, value: &Vec<u32>) -> Self {
|
||||||
Tag::new(
|
Tag::new(
|
||||||
code,
|
code,
|
||||||
value.into_iter().map(|x| x.to_le_bytes()).flatten().collect(),
|
value
|
||||||
|
.into_iter()
|
||||||
|
.map(|x| x.to_le_bytes())
|
||||||
|
.flatten()
|
||||||
|
.collect(),
|
||||||
13,
|
13,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -508,6 +513,8 @@ impl Drop for IJTiffFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl IJTiffFile {
|
impl IJTiffFile {
|
||||||
|
|
||||||
|
/// create new tifffile from path string
|
||||||
pub fn new(path: &str) -> Result<Self> {
|
pub fn new(path: &str) -> Result<Self> {
|
||||||
let mut file = OpenOptions::new()
|
let mut file = OpenOptions::new()
|
||||||
.create(true)
|
.create(true)
|
||||||
@@ -535,10 +542,12 @@ impl IJTiffFile {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// set zstd compression level: -7 ..= 22
|
||||||
pub fn set_compression_level(&mut self, compression_level: i32) {
|
pub fn set_compression_level(&mut self, compression_level: i32) {
|
||||||
self.compression_level = compression_level.max(-7).min(22);
|
self.compression_level = compression_level.max(-7).min(22);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// to be saved in description tag (270)
|
||||||
pub fn description(&self, c_size: usize, z_size: usize, t_size: usize) -> String {
|
pub fn description(&self, c_size: usize, z_size: usize, t_size: usize) -> String {
|
||||||
let mut desc: String = String::from("ImageJ=1.11a");
|
let mut desc: String = String::from("ImageJ=1.11a");
|
||||||
if let Colors::None = self.colors {
|
if let Colors::None = self.colors {
|
||||||
@@ -632,20 +641,12 @@ impl IJTiffFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save<T>(&mut self, frame: ArrayView2<T>, c: usize, z: usize, t: usize) -> Result<()>
|
pub fn save<'a, A, T>(&mut self, frame: A, c: usize, z: usize, t: usize) -> Result<()>
|
||||||
where
|
where
|
||||||
T: Bytes + Clone + Send + Zero + 'static,
|
A: AsArray<'a, T, Ix2>,
|
||||||
|
T: Bytes + Clone + Send + Sync + Zero + 'static,
|
||||||
{
|
{
|
||||||
self.compress_frame(frame.reversed_axes(), c, z, t)?;
|
fn compress<T>(frame: ArcArray2<T>, compression_level: i32) -> CompressedFrame
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compress_frame<T>(&mut self, frame: ArrayView2<T>,
|
|
||||||
c: usize, z: usize, t: usize) -> Result<()>
|
|
||||||
where
|
|
||||||
T: Bytes + Clone + Send + Zero + 'static,
|
|
||||||
{
|
|
||||||
fn compress<T>(frame: Array2<T>, compression_level: i32) -> CompressedFrame
|
|
||||||
where
|
where
|
||||||
T: Bytes + Clone + Zero,
|
T: Bytes + Clone + Zero,
|
||||||
{
|
{
|
||||||
@@ -658,7 +659,7 @@ impl IJTiffFile {
|
|||||||
)
|
)
|
||||||
.max(16)
|
.max(16)
|
||||||
.min(1024);
|
.min(1024);
|
||||||
let tiles = IJTiffFile::tile(frame.view().reversed_axes(), tile_size);
|
let tiles = IJTiffFile::tile(frame.view(), tile_size);
|
||||||
let byte_tiles: Vec<Vec<u8>> = tiles
|
let byte_tiles: Vec<Vec<u8>> = tiles
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|tile| tile.map(|x| x.bytes()).into_iter().flatten().collect())
|
.map(|tile| tile.map(|x| x.bytes()).into_iter().flatten().collect())
|
||||||
@@ -691,7 +692,7 @@ impl IJTiffFile {
|
|||||||
sleep(Duration::from_millis(100));
|
sleep(Duration::from_millis(100));
|
||||||
}
|
}
|
||||||
let compression_level = self.compression_level;
|
let compression_level = self.compression_level;
|
||||||
let frame = frame.to_owned();
|
let frame = frame.into().to_shared();
|
||||||
self.threads.insert(
|
self.threads.insert(
|
||||||
(c, z, t),
|
(c, z, t),
|
||||||
thread::spawn(move || compress(frame, compression_level)),
|
thread::spawn(move || compress(frame, compression_level)),
|
||||||
@@ -906,12 +907,13 @@ impl IJTiffFile {
|
|||||||
let (c, z, t) = self.get_czt(*frame_number, *channel, c_size, z_size);
|
let (c, z, t) = self.get_czt(*frame_number, *channel, c_size, z_size);
|
||||||
println!("c: {c}, z: {z}, t: {t}")
|
println!("c: {c}, z: {z}, t: {t}")
|
||||||
}
|
}
|
||||||
println!("Either you forgot them, \
|
println!(
|
||||||
or an error occurred and the tif file was closed prematurely.")
|
"Either you forgot them, \
|
||||||
|
or an error occurred and the tif file was closed prematurely."
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.file
|
self.file.seek(SeekFrom::Start(where_to_write_next_ifd_offset))?;
|
||||||
.seek(SeekFrom::Start(where_to_write_next_ifd_offset))?;
|
|
||||||
self.file.write(&0u64.to_le_bytes())?;
|
self.file.write(&0u64.to_le_bytes())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,6 @@ fn main() -> Result<()> {
|
|||||||
arr.slice_mut(s![64.., ..64]).fill(1);
|
arr.slice_mut(s![64.., ..64]).fill(1);
|
||||||
arr.slice_mut(s![..64, 64..]).fill(2);
|
arr.slice_mut(s![..64, 64..]).fill(2);
|
||||||
arr.slice_mut(s![64.., 64..]).fill(3);
|
arr.slice_mut(s![64.., 64..]).fill(3);
|
||||||
f.save(arr.view(), 1, 0, 0)?;
|
f.save(&arr, 1, 0, 0)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user