- implement shape in Rust
- implement more readers - fix downloading of bioformats jar - (mostly) compatible with python version
This commit is contained in:
+726
@@ -0,0 +1,726 @@
|
||||
use crate::axes::{Axis, Shape};
|
||||
use crate::error::Error;
|
||||
use crate::view::View;
|
||||
use ndarray::{Array, Dimension, Ix2, Ix5, s};
|
||||
use num::{FromPrimitive, Zero};
|
||||
use ome_metadata::Ome;
|
||||
use regex::Regex;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::any::type_name;
|
||||
use std::collections::HashSet;
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
use std::sync::LazyLock;
|
||||
|
||||
#[cfg(feature = "czi")]
|
||||
pub mod czi;
|
||||
|
||||
#[cfg(feature = "bioformats_rust")]
|
||||
pub mod bioformats_rust;
|
||||
|
||||
#[cfg(feature = "bioformats_java")]
|
||||
pub mod bioformats_java;
|
||||
|
||||
#[cfg(feature = "tiffseq")]
|
||||
pub mod tiffseq;
|
||||
|
||||
#[cfg(feature = "tiff")]
|
||||
pub mod tiff;
|
||||
|
||||
static RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"^([CZTSP])\D+(\d+)$").unwrap());
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct Dimensions {
|
||||
pub c: Option<usize>,
|
||||
pub z: Option<usize>,
|
||||
pub t: Option<usize>,
|
||||
pub s: Option<usize>,
|
||||
pub p: Option<usize>,
|
||||
}
|
||||
|
||||
impl Dimensions {
|
||||
pub fn new(series: usize, position: usize) -> Self {
|
||||
Self {
|
||||
c: None,
|
||||
z: None,
|
||||
t: None,
|
||||
s: Some(series),
|
||||
p: Some(position),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_path<P>(path: P) -> Result<(PathBuf, Self), Error>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let mut path = path.as_ref();
|
||||
let mut new = Self::default();
|
||||
while !path.exists() {
|
||||
let last = path
|
||||
.file_name()
|
||||
.ok_or(Error::InvalidFileName)?
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
path = path.parent().ok_or(Error::NoParent)?;
|
||||
let last_upper = last.to_uppercase();
|
||||
let caps = RE.captures(&last_upper).ok_or(Error::FileDoesNotExist(
|
||||
path.join(&last).display().to_string(),
|
||||
))?;
|
||||
let p = caps[2].parse()?;
|
||||
match &caps[1] {
|
||||
"C" => new.c = Some(p),
|
||||
"Z" => new.z = Some(p),
|
||||
"T" => new.t = Some(p),
|
||||
"S" => new.s = Some(p),
|
||||
"P" => new.p = Some(p),
|
||||
_ => {
|
||||
return Err(Error::FileDoesNotExist(
|
||||
path.join(last).display().to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok((path.to_path_buf(), new))
|
||||
}
|
||||
}
|
||||
|
||||
/// Pixel types (u)int(8/16/32) or float(32/64), (u/i)(64/128) are not included in bioformats
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub enum PixelType {
|
||||
I8,
|
||||
U8,
|
||||
I16,
|
||||
U16,
|
||||
I32,
|
||||
U32,
|
||||
F32,
|
||||
F64,
|
||||
I64,
|
||||
U64,
|
||||
I128,
|
||||
U128,
|
||||
F128,
|
||||
}
|
||||
|
||||
impl PixelType {
|
||||
pub fn bytes_per_pixel(&self) -> usize {
|
||||
match self {
|
||||
PixelType::I8 | PixelType::U8 => 1,
|
||||
PixelType::I16 | PixelType::U16 => 2,
|
||||
PixelType::I32 | PixelType::U32 | PixelType::F32 => 4,
|
||||
PixelType::I64 | PixelType::U64 | PixelType::F64 => 8,
|
||||
PixelType::I128 | PixelType::U128 | PixelType::F128 => 16,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Struct containing frame data in one of eight pixel types. Cast to `Array2<T>` using try_into.
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ArrayT<D: Dimension> {
|
||||
I8(Array<i8, D>),
|
||||
U8(Array<u8, D>),
|
||||
I16(Array<i16, D>),
|
||||
U16(Array<u16, D>),
|
||||
I32(Array<i32, D>),
|
||||
U32(Array<u32, D>),
|
||||
F32(Array<f32, D>),
|
||||
F64(Array<f64, D>),
|
||||
I64(Array<i64, D>),
|
||||
U64(Array<u64, D>),
|
||||
I128(Array<i128, D>),
|
||||
U128(Array<u128, D>),
|
||||
F128(Array<f64, D>), // f128 is nightly
|
||||
}
|
||||
|
||||
pub(crate) type Frame = ArrayT<Ix2>;
|
||||
|
||||
pub trait Reader: Clone + Sized + Debug + Send + Hash + Into<DynReader> {
|
||||
fn new<P>(path: P, series: usize, position: usize) -> Result<Self, Error>
|
||||
where
|
||||
P: AsRef<Path>;
|
||||
|
||||
fn reader_name(&self) -> String {
|
||||
type_name::<Self>().to_string()
|
||||
}
|
||||
|
||||
// TODO: read from file if present
|
||||
fn metadata(&self) -> Result<Ome, Error>;
|
||||
|
||||
/// get a sliceable view on the image file
|
||||
fn view(&self) -> View<Ix5, Self> {
|
||||
let shape = self.shape();
|
||||
let slice = s![0..shape.c, 0..shape.z, 0..shape.t, 0..shape.y, 0..shape.x,];
|
||||
View::new(
|
||||
self.clone(),
|
||||
slice.as_ref().to_vec(),
|
||||
vec![Axis::C, Axis::Z, Axis::T, Axis::Y, Axis::X],
|
||||
)
|
||||
}
|
||||
|
||||
/// Retrieve fame at channel c, slize z and time t.
|
||||
#[allow(clippy::if_same_then_else)]
|
||||
fn get_frame(&self, c: usize, z: usize, t: usize) -> Result<Frame, Error>;
|
||||
|
||||
fn path(&self) -> &Path;
|
||||
fn series(&self) -> usize;
|
||||
fn position(&self) -> usize;
|
||||
fn shape(&self) -> &Shape;
|
||||
fn pixel_type(&self) -> &PixelType;
|
||||
fn get_available_positions<P>(path: P, series: usize) -> Result<HashSet<usize>, Error>
|
||||
where
|
||||
P: AsRef<Path>;
|
||||
fn get_available_series<P>(path: P) -> Result<HashSet<usize>, Error>
|
||||
where
|
||||
P: AsRef<Path>;
|
||||
}
|
||||
|
||||
impl TryFrom<i32> for PixelType {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: i32) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
0 => Ok(PixelType::I8),
|
||||
1 => Ok(PixelType::U8),
|
||||
2 => Ok(PixelType::I16),
|
||||
3 => Ok(PixelType::U16),
|
||||
4 => Ok(PixelType::I32),
|
||||
5 => Ok(PixelType::U32),
|
||||
6 => Ok(PixelType::F32),
|
||||
7 => Ok(PixelType::F64),
|
||||
8 => Ok(PixelType::I64),
|
||||
9 => Ok(PixelType::U64),
|
||||
10 => Ok(PixelType::I128),
|
||||
11 => Ok(PixelType::U128),
|
||||
12 => Ok(PixelType::F128),
|
||||
_ => Err(Error::UnknownPixelType(value.to_string())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for PixelType {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s.to_lowercase().as_str() {
|
||||
"int8" | "i8" => Ok(PixelType::I8),
|
||||
"uint8" | "u8" => Ok(PixelType::U8),
|
||||
"int16" | "i16" => Ok(PixelType::I16),
|
||||
"uint16" | "u16" => Ok(PixelType::U16),
|
||||
"int32" | "i32" => Ok(PixelType::I32),
|
||||
"uint32" | "u32" => Ok(PixelType::U32),
|
||||
"float" | "f32" | "float32" => Ok(PixelType::F32),
|
||||
"double" | "f64" | "float64" => Ok(PixelType::F64),
|
||||
"int64" | "i64" => Ok(PixelType::I64),
|
||||
"uint64" | "u64" => Ok(PixelType::U64),
|
||||
"int128" | "i128" => Ok(PixelType::I128),
|
||||
"uint128" | "u128" => Ok(PixelType::U128),
|
||||
"extended" | "f128" => Ok(PixelType::F128),
|
||||
_ => Err(Error::UnknownPixelType(s.to_string())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_frame_cast {
|
||||
($($t:tt: $s:ident $(,)?)*) => {
|
||||
$(
|
||||
impl<D: Dimension> From<Array<$t, D>> for ArrayT<D> {
|
||||
fn from(value: Array<$t, D>) -> Self {
|
||||
ArrayT::$s(value)
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
impl_frame_cast! {
|
||||
u8: U8
|
||||
i8: I8
|
||||
i16: I16
|
||||
u16: U16
|
||||
i32: I32
|
||||
u32: U32
|
||||
f32: F32
|
||||
f64: F64
|
||||
i64: I64
|
||||
u64: U64
|
||||
i128: I128
|
||||
u128: U128
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
impl_frame_cast! {
|
||||
usize: UINT32
|
||||
isize: INT32
|
||||
}
|
||||
|
||||
impl<D, T> TryInto<Array<T, D>> for ArrayT<D>
|
||||
where
|
||||
D: Dimension,
|
||||
T: FromPrimitive + Zero + 'static,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
fn try_into(self) -> Result<Array<T, D>, Self::Error> {
|
||||
let mut err = Ok(());
|
||||
let arr = match self {
|
||||
ArrayT::I8(v) => v.mapv_into_any(|x| {
|
||||
T::from_i8(x).unwrap_or_else(|| {
|
||||
err = Err(Error::Cast(x.to_string(), type_name::<T>().to_string()));
|
||||
T::zero()
|
||||
})
|
||||
}),
|
||||
ArrayT::U8(v) => v.mapv_into_any(|x| {
|
||||
T::from_u8(x).unwrap_or_else(|| {
|
||||
err = Err(Error::Cast(x.to_string(), type_name::<T>().to_string()));
|
||||
T::zero()
|
||||
})
|
||||
}),
|
||||
ArrayT::I16(v) => v.mapv_into_any(|x| {
|
||||
T::from_i16(x).unwrap_or_else(|| {
|
||||
err = Err(Error::Cast(x.to_string(), type_name::<T>().to_string()));
|
||||
T::zero()
|
||||
})
|
||||
}),
|
||||
ArrayT::U16(v) => v.mapv_into_any(|x| {
|
||||
T::from_u16(x).unwrap_or_else(|| {
|
||||
err = Err(Error::Cast(x.to_string(), type_name::<T>().to_string()));
|
||||
T::zero()
|
||||
})
|
||||
}),
|
||||
ArrayT::I32(v) => v.mapv_into_any(|x| {
|
||||
T::from_i32(x).unwrap_or_else(|| {
|
||||
err = Err(Error::Cast(x.to_string(), type_name::<T>().to_string()));
|
||||
T::zero()
|
||||
})
|
||||
}),
|
||||
ArrayT::U32(v) => v.mapv_into_any(|x| {
|
||||
T::from_u32(x).unwrap_or_else(|| {
|
||||
err = Err(Error::Cast(x.to_string(), type_name::<T>().to_string()));
|
||||
T::zero()
|
||||
})
|
||||
}),
|
||||
ArrayT::F32(v) => v.mapv_into_any(|x| {
|
||||
T::from_f32(x).unwrap_or_else(|| {
|
||||
err = Err(Error::Cast(x.to_string(), type_name::<T>().to_string()));
|
||||
T::zero()
|
||||
})
|
||||
}),
|
||||
ArrayT::F64(v) | ArrayT::F128(v) => v.mapv_into_any(|x| {
|
||||
T::from_f64(x).unwrap_or_else(|| {
|
||||
err = Err(Error::Cast(x.to_string(), type_name::<T>().to_string()));
|
||||
T::zero()
|
||||
})
|
||||
}),
|
||||
ArrayT::I64(v) => v.mapv_into_any(|x| {
|
||||
T::from_i64(x).unwrap_or_else(|| {
|
||||
err = Err(Error::Cast(x.to_string(), type_name::<T>().to_string()));
|
||||
T::zero()
|
||||
})
|
||||
}),
|
||||
ArrayT::U64(v) => v.mapv_into_any(|x| {
|
||||
T::from_u64(x).unwrap_or_else(|| {
|
||||
err = Err(Error::Cast(x.to_string(), type_name::<T>().to_string()));
|
||||
T::zero()
|
||||
})
|
||||
}),
|
||||
ArrayT::I128(v) => v.mapv_into_any(|x| {
|
||||
T::from_i128(x).unwrap_or_else(|| {
|
||||
err = Err(Error::Cast(x.to_string(), type_name::<T>().to_string()));
|
||||
T::zero()
|
||||
})
|
||||
}),
|
||||
ArrayT::U128(v) => v.mapv_into_any(|x| {
|
||||
T::from_u128(x).unwrap_or_else(|| {
|
||||
err = Err(Error::Cast(x.to_string(), type_name::<T>().to_string()));
|
||||
T::zero()
|
||||
})
|
||||
}),
|
||||
};
|
||||
match err {
|
||||
Err(err) => Err(err),
|
||||
Ok(()) => Ok(arr),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, Hash)]
|
||||
pub enum DynReader {
|
||||
#[cfg(feature = "tiff")]
|
||||
Tiff(tiff::TiffReader),
|
||||
#[cfg(feature = "tiffseq")]
|
||||
TiffSeq(tiffseq::TiffSeqReader),
|
||||
#[cfg(feature = "czi")]
|
||||
Czi(czi::CziReader),
|
||||
#[cfg(feature = "bioformats_rust")]
|
||||
BioFormatsRust(bioformats_rust::BioFormatsRustReader),
|
||||
#[cfg(feature = "bioformats_java")]
|
||||
BioFormatsJava(bioformats_java::BioFormatsJavaReader),
|
||||
}
|
||||
|
||||
impl Reader for DynReader {
|
||||
fn new<P>(path: P, series: usize, position: usize) -> Result<Self, Error>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let mut errors = Vec::<String>::new();
|
||||
#[cfg(feature = "tiff")]
|
||||
match tiff::TiffReader::new(&path, series, position) {
|
||||
Ok(reader) => return Ok(DynReader::Tiff(reader)),
|
||||
Err(err) => errors.push(format!("TiffReader: {}", err)),
|
||||
}
|
||||
#[cfg(feature = "tiffseq")]
|
||||
match tiffseq::TiffSeqReader::new(&path, series, position) {
|
||||
Ok(reader) => return Ok(DynReader::TiffSeq(reader)),
|
||||
Err(err) => errors.push(format!("TiffseqReader: {}", err)),
|
||||
}
|
||||
#[cfg(feature = "czi")]
|
||||
match czi::CziReader::new(&path, series, position) {
|
||||
Ok(reader) => return Ok(DynReader::Czi(reader)),
|
||||
Err(err) => errors.push(format!("CziReader: {}", err)),
|
||||
}
|
||||
#[cfg(feature = "bioformats_rust")]
|
||||
match bioformats_rust::BioFormatsRustReader::new(&path, series, position) {
|
||||
Ok(reader) => return Ok(DynReader::BioFormatsRust(reader)),
|
||||
Err(err) => errors.push(format!("BioformatsRustReader: {}", err)),
|
||||
}
|
||||
#[cfg(feature = "bioformats_java")]
|
||||
match bioformats_java::BioFormatsJavaReader::new(&path, series, position) {
|
||||
Ok(reader) => return Ok(DynReader::BioFormatsJava(reader)),
|
||||
Err(err) => errors.push(format!("BioformatsReader: {}", err)),
|
||||
}
|
||||
Err(Error::NoReader(
|
||||
path.as_ref().display().to_string(),
|
||||
errors.join("\n"),
|
||||
))
|
||||
}
|
||||
|
||||
fn reader_name(&self) -> String {
|
||||
let name = match self {
|
||||
#[cfg(feature = "tiff")]
|
||||
DynReader::Tiff(r) => r.reader_name(),
|
||||
#[cfg(feature = "tiffseq")]
|
||||
DynReader::TiffSeq(r) => r.reader_name(),
|
||||
#[cfg(feature = "czi")]
|
||||
DynReader::Czi(r) => r.reader_name(),
|
||||
#[cfg(feature = "bioformats_rust")]
|
||||
DynReader::BioFormatsRust(r) => r.reader_name(),
|
||||
#[cfg(feature = "bioformats_java")]
|
||||
DynReader::BioFormatsJava(r) => r.reader_name(),
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => unreachable!(),
|
||||
};
|
||||
format!("DynReader<{}>", name)
|
||||
}
|
||||
|
||||
fn metadata(&self) -> Result<Ome, Error> {
|
||||
Ok(match self {
|
||||
#[cfg(feature = "tiff")]
|
||||
DynReader::Tiff(r) => r.metadata()?,
|
||||
#[cfg(feature = "tiffseq")]
|
||||
DynReader::TiffSeq(r) => r.metadata()?,
|
||||
#[cfg(feature = "czi")]
|
||||
DynReader::Czi(r) => r.metadata()?,
|
||||
#[cfg(feature = "bioformats_rust")]
|
||||
DynReader::BioFormatsRust(r) => r.metadata()?,
|
||||
#[cfg(feature = "bioformats_java")]
|
||||
DynReader::BioFormatsJava(r) => r.metadata()?,
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => unreachable!(),
|
||||
})
|
||||
}
|
||||
|
||||
fn get_frame(&self, c: usize, z: usize, t: usize) -> Result<Frame, Error> {
|
||||
match self {
|
||||
#[cfg(feature = "tiff")]
|
||||
DynReader::Tiff(r) => r.get_frame(c, z, t),
|
||||
#[cfg(feature = "tiffseq")]
|
||||
DynReader::TiffSeq(r) => r.get_frame(c, z, t),
|
||||
#[cfg(feature = "czi")]
|
||||
DynReader::Czi(r) => r.get_frame(c, z, t),
|
||||
#[cfg(feature = "bioformats_rust")]
|
||||
DynReader::BioFormatsRust(r) => r.get_frame(c, z, t),
|
||||
#[cfg(feature = "bioformats_java")]
|
||||
DynReader::BioFormatsJava(r) => r.get_frame(c, z, t),
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn path(&self) -> &Path {
|
||||
match self {
|
||||
#[cfg(feature = "tiff")]
|
||||
DynReader::Tiff(r) => r.path(),
|
||||
#[cfg(feature = "tiffseq")]
|
||||
DynReader::TiffSeq(r) => r.path(),
|
||||
#[cfg(feature = "czi")]
|
||||
DynReader::Czi(r) => r.path(),
|
||||
#[cfg(feature = "bioformats_rust")]
|
||||
DynReader::BioFormatsRust(r) => r.path(),
|
||||
#[cfg(feature = "bioformats_java")]
|
||||
DynReader::BioFormatsJava(r) => r.path(),
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn series(&self) -> usize {
|
||||
match self {
|
||||
#[cfg(feature = "tiff")]
|
||||
DynReader::Tiff(r) => r.series(),
|
||||
#[cfg(feature = "tiffseq")]
|
||||
DynReader::TiffSeq(r) => r.series(),
|
||||
#[cfg(feature = "czi")]
|
||||
DynReader::Czi(r) => r.series(),
|
||||
#[cfg(feature = "bioformats_rust")]
|
||||
DynReader::BioFormatsRust(r) => r.series(),
|
||||
#[cfg(feature = "bioformats_java")]
|
||||
DynReader::BioFormatsJava(r) => r.series(),
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn position(&self) -> usize {
|
||||
match self {
|
||||
#[cfg(feature = "tiff")]
|
||||
DynReader::Tiff(r) => r.position(),
|
||||
#[cfg(feature = "tiffseq")]
|
||||
DynReader::TiffSeq(r) => r.position(),
|
||||
#[cfg(feature = "czi")]
|
||||
DynReader::Czi(r) => r.position(),
|
||||
#[cfg(feature = "bioformats_rust")]
|
||||
DynReader::BioFormatsRust(r) => r.position(),
|
||||
#[cfg(feature = "bioformats_java")]
|
||||
DynReader::BioFormatsJava(r) => r.position(),
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn shape(&self) -> &Shape {
|
||||
match self {
|
||||
#[cfg(feature = "tiff")]
|
||||
DynReader::Tiff(r) => r.shape(),
|
||||
#[cfg(feature = "tiffseq")]
|
||||
DynReader::TiffSeq(r) => r.shape(),
|
||||
#[cfg(feature = "czi")]
|
||||
DynReader::Czi(r) => r.shape(),
|
||||
#[cfg(feature = "bioformats_rust")]
|
||||
DynReader::BioFormatsRust(r) => r.shape(),
|
||||
#[cfg(feature = "bioformats_java")]
|
||||
DynReader::BioFormatsJava(r) => r.shape(),
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn pixel_type(&self) -> &PixelType {
|
||||
match self {
|
||||
#[cfg(feature = "tiff")]
|
||||
DynReader::Tiff(r) => r.pixel_type(),
|
||||
#[cfg(feature = "tiffseq")]
|
||||
DynReader::TiffSeq(r) => r.pixel_type(),
|
||||
#[cfg(feature = "czi")]
|
||||
DynReader::Czi(r) => r.pixel_type(),
|
||||
#[cfg(feature = "bioformats_rust")]
|
||||
DynReader::BioFormatsRust(r) => r.pixel_type(),
|
||||
#[cfg(feature = "bioformats_java")]
|
||||
DynReader::BioFormatsJava(r) => r.pixel_type(),
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_available_positions<P>(path: P, series: usize) -> Result<HashSet<usize>, Error>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let mut errors = Vec::<String>::new();
|
||||
#[cfg(feature = "tiff")]
|
||||
match tiff::TiffReader::get_available_positions(&path, series) {
|
||||
Ok(positions) => return Ok(positions),
|
||||
Err(e) => errors.push(format!("TiffReader: {}", e)),
|
||||
}
|
||||
#[cfg(feature = "tiffseq")]
|
||||
match tiffseq::TiffSeqReader::get_available_positions(&path, series) {
|
||||
Ok(positions) => return Ok(positions),
|
||||
Err(e) => errors.push(format!("TiffSeqReader: {}", e)),
|
||||
}
|
||||
#[cfg(feature = "czi")]
|
||||
match czi::CziReader::get_available_positions(&path, series) {
|
||||
Ok(positions) => return Ok(positions),
|
||||
Err(e) => errors.push(format!("CziReader: {}", e)),
|
||||
}
|
||||
#[cfg(feature = "bioformats_rust")]
|
||||
match bioformats_rust::BioFormatsRustReader::get_available_positions(&path, series) {
|
||||
Ok(positions) => return Ok(positions),
|
||||
Err(e) => errors.push(format!("BioFormatsRustReader: {}", e)),
|
||||
}
|
||||
#[cfg(feature = "bioformats_java")]
|
||||
match bioformats_java::BioFormatsJavaReader::get_available_positions(&path, series) {
|
||||
Ok(positions) => return Ok(positions),
|
||||
Err(e) => errors.push(format!("BioFormatsReader: {}", e)),
|
||||
}
|
||||
Err(Error::NoReader(
|
||||
path.as_ref().display().to_string(),
|
||||
errors.join("\n"),
|
||||
))
|
||||
}
|
||||
|
||||
fn get_available_series<P>(path: P) -> Result<HashSet<usize>, Error>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let mut errors = Vec::<String>::new();
|
||||
#[cfg(feature = "tiff")]
|
||||
match tiff::TiffReader::get_available_series(&path) {
|
||||
Ok(positions) => return Ok(positions),
|
||||
Err(e) => errors.push(format!("TiffReader: {}", e)),
|
||||
}
|
||||
#[cfg(feature = "tiffseq")]
|
||||
match tiffseq::TiffSeqReader::get_available_series(&path) {
|
||||
Ok(positions) => return Ok(positions),
|
||||
Err(e) => errors.push(format!("TiffSeqReader: {}", e)),
|
||||
}
|
||||
#[cfg(feature = "czi")]
|
||||
match czi::CziReader::get_available_series(&path) {
|
||||
Ok(positions) => return Ok(positions),
|
||||
Err(e) => errors.push(format!("CziReader: {}", e)),
|
||||
}
|
||||
#[cfg(feature = "bioformats_rust")]
|
||||
match bioformats_rust::BioFormatsRustReader::get_available_series(&path) {
|
||||
Ok(positions) => return Ok(positions),
|
||||
Err(e) => errors.push(format!("BioFormatsRustReader: {}", e)),
|
||||
}
|
||||
#[cfg(feature = "bioformats_java")]
|
||||
match bioformats_java::BioFormatsJavaReader::get_available_series(&path) {
|
||||
Ok(positions) => return Ok(positions),
|
||||
Err(e) => errors.push(format!("BioFormatsReader: {}", e)),
|
||||
}
|
||||
Err(Error::NoReader(
|
||||
path.as_ref().display().to_string(),
|
||||
errors.join("\n"),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl DynReader {
|
||||
pub fn from_path_select_reader<P, R>(path: P, reader: R) -> Result<DynReader, Error>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
R: AsRef<str>,
|
||||
{
|
||||
let path = path.as_ref();
|
||||
let (path, dimensions) = Dimensions::parse_path(path)?;
|
||||
let reader = reader.as_ref();
|
||||
let reader = match reader.to_lowercase().as_str() {
|
||||
#[cfg(feature = "tiff")]
|
||||
"tif" => Ok(DynReader::Tiff(tiff::TiffReader::new(
|
||||
path,
|
||||
dimensions.s.unwrap_or(0),
|
||||
dimensions.p.unwrap_or(0),
|
||||
)?)),
|
||||
#[cfg(feature = "tiffseq")]
|
||||
"tiffseq" => Ok(DynReader::TiffSeq(tiffseq::TiffSeqReader::new(
|
||||
path,
|
||||
dimensions.s.unwrap_or(0),
|
||||
dimensions.p.unwrap_or(0),
|
||||
)?)),
|
||||
#[cfg(feature = "czi")]
|
||||
"czi" => Ok(DynReader::Czi(czi::CziReader::new(
|
||||
path,
|
||||
dimensions.s.unwrap_or(0),
|
||||
dimensions.p.unwrap_or(0),
|
||||
)?)),
|
||||
#[cfg(feature = "bioformats_rust")]
|
||||
"bioformats_rust" => Ok(DynReader::BioFormatsRust(
|
||||
bioformats_rust::BioFormatsRustReader::new(
|
||||
path,
|
||||
dimensions.s.unwrap_or(0),
|
||||
dimensions.p.unwrap_or(0),
|
||||
)?,
|
||||
)),
|
||||
#[cfg(feature = "bioformats_java")]
|
||||
"bioformats_java" => Ok(DynReader::BioFormatsJava(
|
||||
bioformats_java::BioFormatsJavaReader::new(
|
||||
path,
|
||||
dimensions.s.unwrap_or(0),
|
||||
dimensions.p.unwrap_or(0),
|
||||
)?,
|
||||
)),
|
||||
_ => Err(Error::Parse(reader.to_string())),
|
||||
}?;
|
||||
Ok(reader)
|
||||
}
|
||||
|
||||
pub fn get_available_positions_select_reader<P, R>(
|
||||
path: P,
|
||||
series: usize,
|
||||
reader: Option<R>,
|
||||
) -> Result<HashSet<usize>, Error>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
R: AsRef<str>,
|
||||
{
|
||||
Ok(if let Some(reader) = reader {
|
||||
let reader = reader.as_ref();
|
||||
match reader.to_lowercase().as_str() {
|
||||
#[cfg(feature = "tiff")]
|
||||
"tif" => Ok(tiff::TiffReader::get_available_positions(path, series)?),
|
||||
#[cfg(feature = "tiffseq")]
|
||||
"tiffseq" => Ok(tiffseq::TiffSeqReader::get_available_positions(
|
||||
path, series,
|
||||
)?),
|
||||
#[cfg(feature = "czi")]
|
||||
"czi" => Ok(czi::CziReader::get_available_positions(path, series)?),
|
||||
#[cfg(feature = "bioformats_rust")]
|
||||
"bioformats_rust" => Ok(
|
||||
bioformats_rust::BioFormatsRustReader::get_available_positions(path, series)?,
|
||||
),
|
||||
#[cfg(feature = "bioformats_java")]
|
||||
"bioformats_java" => Ok(
|
||||
bioformats_java::BioFormatsJavaReader::get_available_positions(path, series)?,
|
||||
),
|
||||
_ => Err(Error::Parse(reader.to_string())),
|
||||
}?
|
||||
} else {
|
||||
DynReader::get_available_positions(&path, series)?
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_available_series_select_reader<P, R>(
|
||||
path: P,
|
||||
reader: Option<R>,
|
||||
) -> Result<HashSet<usize>, Error>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
R: AsRef<str>,
|
||||
{
|
||||
Ok(if let Some(reader) = reader {
|
||||
let reader = reader.as_ref();
|
||||
match reader.to_lowercase().as_str() {
|
||||
#[cfg(feature = "tiff")]
|
||||
"tif" => Ok(tiff::TiffReader::get_available_series(path)?),
|
||||
#[cfg(feature = "tiffseq")]
|
||||
"tiffseq" => Ok(tiffseq::TiffSeqReader::get_available_series(path)?),
|
||||
#[cfg(feature = "czi")]
|
||||
"czi" => Ok(czi::CziReader::get_available_series(path)?),
|
||||
#[cfg(feature = "bioformats_rust")]
|
||||
"bioformats_rust" => Ok(
|
||||
bioformats_rust::BioFormatsRustReader::get_available_series(path)?,
|
||||
),
|
||||
#[cfg(feature = "bioformats_java")]
|
||||
"bioformats_java" => Ok(
|
||||
bioformats_java::BioFormatsJavaReader::get_available_series(path)?,
|
||||
),
|
||||
_ => Err(Error::Parse(reader.to_string())),
|
||||
}?
|
||||
} else {
|
||||
DynReader::get_available_series(&path)?
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user