- implement shape in Rust
- implement more readers - fix downloading of bioformats jar - (mostly) compatible with python version
This commit is contained in:
@@ -0,0 +1,612 @@
|
||||
use crate::error::Error;
|
||||
use ndarray::Array2;
|
||||
use ome_metadata::Ome;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Debug;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub use crate::readers::{ArrayT, PixelType, Reader};
|
||||
use crate::readers::{DynReader, Frame, Shape};
|
||||
use j4rs::{Instance, InvocationArg, Jvm, JvmBuilder};
|
||||
use std::cell::OnceCell;
|
||||
use std::collections::HashSet;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Mutex;
|
||||
use thread_local::ThreadLocal;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/constants.rs"));
|
||||
|
||||
thread_local! {
|
||||
static JVM: OnceCell<Rc<Jvm>> = const { OnceCell::new() }
|
||||
}
|
||||
|
||||
static DOWNLOAD_LOCK: Mutex<()> = Mutex::new(());
|
||||
static JVM_BUILT: Mutex<bool> = Mutex::new(false);
|
||||
|
||||
/// Ensure 1 jvm per thread
|
||||
fn jvm() -> Rc<Jvm> {
|
||||
JVM.with(|cell| {
|
||||
cell.get_or_init(move || {
|
||||
#[cfg(feature = "python")]
|
||||
let path = crate::py::ndbioimage_file();
|
||||
|
||||
#[cfg(not(feature = "python"))]
|
||||
let path = std::env::current_exe()
|
||||
.unwrap()
|
||||
.parent()
|
||||
.unwrap()
|
||||
.to_path_buf();
|
||||
|
||||
let class_path = if path.join("jassets").exists() {
|
||||
path.as_path()
|
||||
} else {
|
||||
path.parent().unwrap()
|
||||
};
|
||||
|
||||
// download jars if needed, but make sure only one thread will do this
|
||||
{
|
||||
let _guard = DOWNLOAD_LOCK.lock().unwrap();
|
||||
let jassets = class_path.join("jassets");
|
||||
if !jassets.exists() {
|
||||
std::fs::create_dir_all(&jassets).unwrap();
|
||||
}
|
||||
|
||||
if !jassets.join(format!("j4rs-{}-jar-with-dependencies.jar", J4RS_VERSION)).exists() {
|
||||
println!("downloading j4rs-{}-jar-with-dependencies.jar into {}", J4RS_VERSION, jassets.display());
|
||||
let download = downloader::Download::new(&format!(
|
||||
"https://github.com/astonbitecode/j4rs/raw/v{}/rust/jassets/j4rs-{}-jar-with-dependencies.jar",
|
||||
J4RS_VERSION, J4RS_VERSION
|
||||
));
|
||||
let mut downloader = downloader::Downloader::builder()
|
||||
.download_folder(&jassets)
|
||||
.build().unwrap();
|
||||
downloader
|
||||
.download(&[download]).unwrap()
|
||||
.into_iter()
|
||||
.collect::<Result<Vec<_>, _>>().unwrap();
|
||||
}
|
||||
|
||||
if !jassets.join(format!("bioformats_package-{}.jar", BIOFORMATS_VERSION)).exists() {
|
||||
println!("downloading bioformats_package-{}.jar into {}", BIOFORMATS_VERSION, jassets.display());
|
||||
let download = downloader::Download::new(&format!(
|
||||
"https://artifacts.openmicroscopy.org/artifactory/ome.releases/ome/bioformats_package/{}/bioformats_package-{}.jar",
|
||||
BIOFORMATS_VERSION, BIOFORMATS_VERSION
|
||||
));
|
||||
let mut downloader = downloader::Downloader::builder()
|
||||
.download_folder(&jassets)
|
||||
.build().unwrap();
|
||||
downloader
|
||||
.download(&[download]).unwrap()
|
||||
.into_iter()
|
||||
.collect::<Result<Vec<_>, _>>().unwrap();
|
||||
}
|
||||
|
||||
#[cfg(feature = "gpl-formats")]
|
||||
if !jassets.join(format!("formats-gpl-{}.jar", BIOFORMATS_VERSION)).exists() {
|
||||
println!("downloading formats-gpl-{}.jar into {}", BIOFORMATS_VERSION, jassets.display());
|
||||
let download = downloader::Download::new(&format!(
|
||||
"https://artifacts.openmicroscopy.org/artifactory/ome.releases/ome/formats-gpl/{}/formats-gpl-{}.jar",
|
||||
BIOFORMATS_VERSION, BIOFORMATS_VERSION
|
||||
));
|
||||
let mut downloader = downloader::Downloader::builder()
|
||||
.download_folder(&jassets)
|
||||
.build().unwrap();
|
||||
downloader
|
||||
.download(&[download]).unwrap()
|
||||
.into_iter()
|
||||
.collect::<Result<Vec<_>, _>>().unwrap();
|
||||
}
|
||||
}
|
||||
{
|
||||
let mut jvm_built = JVM_BUILT.lock().unwrap();
|
||||
Rc::new(if *jvm_built {
|
||||
Jvm::attach_thread().expect("Failed to attach to JVM")
|
||||
} else {
|
||||
*jvm_built = true;
|
||||
JvmBuilder::new()
|
||||
.skip_setting_native_lib()
|
||||
.with_base_path(class_path.to_str().unwrap())
|
||||
.build()
|
||||
.expect("Failed to build JVM")
|
||||
})
|
||||
}
|
||||
})
|
||||
.clone()
|
||||
})
|
||||
}
|
||||
|
||||
macro_rules! method_return {
|
||||
($R:ty$(|c)?) => { Result<$R, Error> };
|
||||
() => { Result<(), Error> };
|
||||
}
|
||||
|
||||
macro_rules! method_arg {
|
||||
($n:tt: $t:ty|p) => {
|
||||
InvocationArg::try_from($n)?.into_primitive()?
|
||||
};
|
||||
($n:tt: $t:ty) => {
|
||||
InvocationArg::try_from($n)?
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! method {
|
||||
($name:ident, $method:expr $(,[$($n:tt: $t:ty$(|$p:tt)?),*])? $(=> $tt:ty$(|$c:tt)?)?) => {
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn $name(&self, $($($n: $t),*)?) -> method_return!($($tt)?) {
|
||||
let args: Vec<InvocationArg> = vec![$($( method_arg!($n:$t$(|$p)?) ),*)?];
|
||||
let _result = jvm().invoke(&self.0, $method, &args)?;
|
||||
|
||||
macro_rules! method_result {
|
||||
($R:ty|c) => {
|
||||
Ok(jvm().to_rust(_result)?)
|
||||
};
|
||||
($R:ty|d) => {
|
||||
Ok(jvm().to_rust_deserialized(_result)?)
|
||||
};
|
||||
($R:ty) => {
|
||||
Ok(_result)
|
||||
};
|
||||
() => {
|
||||
Ok(())
|
||||
};
|
||||
}
|
||||
|
||||
method_result!($($tt$(|$c)?)?)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn transmute_vec<T, U>(vec: Vec<T>) -> Vec<U> {
|
||||
unsafe {
|
||||
// Ensure the original vector is not dropped.
|
||||
let mut v_clone = std::mem::ManuallyDrop::new(vec);
|
||||
Vec::from_raw_parts(
|
||||
v_clone.as_mut_ptr() as *mut U,
|
||||
v_clone.len(),
|
||||
v_clone.capacity(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper around bioformats java class loci.common.DebugTools
|
||||
pub struct DebugTools;
|
||||
|
||||
impl DebugTools {
|
||||
/// set debug root level: ERROR, DEBUG, TRACE, INFO, OFF
|
||||
pub fn set_root_level(level: &str) -> Result<(), Error> {
|
||||
jvm().invoke_static(
|
||||
"loci.common.DebugTools",
|
||||
"setRootLevel",
|
||||
&[InvocationArg::try_from(level)?],
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper around bioformats java class loci.formats.ChannelSeparator
|
||||
pub(crate) struct ChannelSeparator(Instance);
|
||||
|
||||
impl ChannelSeparator {
|
||||
pub(crate) fn new(image_reader: &ImageReader) -> Result<Self, Error> {
|
||||
let jvm = jvm();
|
||||
let channel_separator = jvm.create_instance(
|
||||
"loci.formats.ChannelSeparator",
|
||||
&[InvocationArg::from(jvm.clone_instance(&image_reader.0)?)],
|
||||
)?;
|
||||
Ok(ChannelSeparator(channel_separator))
|
||||
}
|
||||
|
||||
pub(crate) fn open_bytes(&self, index: i32) -> Result<Vec<u8>, Error> {
|
||||
Ok(transmute_vec(self.open_bi8(index)?))
|
||||
}
|
||||
|
||||
method!(open_bi8, "openBytes", [index: i32|p] => Vec<i8>|c);
|
||||
method!(get_index, "getIndex", [z: i32|p, c: i32|p, t: i32|p] => i32|c);
|
||||
}
|
||||
|
||||
/// Wrapper around bioformats java class loci.formats.ImageReader
|
||||
pub struct ImageReader(Instance);
|
||||
|
||||
impl Drop for ImageReader {
|
||||
fn drop(&mut self) {
|
||||
self.close().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl ImageReader {
|
||||
pub(crate) fn new() -> Result<Self, Error> {
|
||||
let reader = jvm().create_instance("loci.formats.ImageReader", InvocationArg::empty())?;
|
||||
Ok(ImageReader(reader))
|
||||
}
|
||||
|
||||
pub(crate) fn open_bytes(&self, index: i32) -> Result<Vec<u8>, Error> {
|
||||
Ok(transmute_vec(self.open_bi8(index)?))
|
||||
}
|
||||
|
||||
pub(crate) fn ome_xml(&self) -> Result<String, Error> {
|
||||
let mds = self.get_metadata_store()?;
|
||||
Ok(jvm()
|
||||
.chain(&mds)?
|
||||
.cast("loci.formats.ome.OMEPyramidStore")?
|
||||
.invoke("dumpXML", InvocationArg::empty())?
|
||||
.to_rust()?)
|
||||
}
|
||||
|
||||
method!(close, "close");
|
||||
method!(is_indexed, "isIndexed" => bool|c);
|
||||
method!(is_interleaved, "isInterleaved" => bool|c);
|
||||
method!(is_little_endian, "isLittleEndian" => bool|c);
|
||||
method!(is_rgb, "isRGB" => bool|c);
|
||||
method!(get_8bit_lookup_table, "get8BitLookupTable" => Instance);
|
||||
method!(get_16bit_lookup_table, "get16BitLookupTable" => Instance);
|
||||
method!(get_dimension_order, "getDimensionOrder" => String|c);
|
||||
method!(set_id, "setId", [id: &str]);
|
||||
method!(get_index, "getIndex", [z: i32|p, c: i32|p, t: i32|p] => i32|c);
|
||||
method!(set_metadata_store, "setMetadataStore", [ome_data: Instance]);
|
||||
method!(get_metadata_store, "getMetadataStore" => Instance);
|
||||
method!(get_pixel_type, "getPixelType" => i32|c);
|
||||
method!(get_rgb_channel_count, "getRGBChannelCount" => i32|c);
|
||||
method!(get_series, "getSeries" => i32|c);
|
||||
method!(set_series, "setSeries", [series: i32|p]);
|
||||
method!(get_series_count, "getSeriesCount" => i32|c);
|
||||
method!(get_size_x, "getSizeX" => i32|c);
|
||||
method!(get_size_y, "getSizeY" => i32|c);
|
||||
method!(get_size_c, "getSizeC" => i32|c);
|
||||
method!(get_size_t, "getSizeT" => i32|c);
|
||||
method!(get_size_z, "getSizeZ" => i32|c);
|
||||
method!(open_bi8, "openBytes", [index: i32|p] => Vec<i8>|c);
|
||||
}
|
||||
|
||||
/// Wrapper around bioformats java class loci.formats.MetadataTools
|
||||
pub(crate) struct MetadataTools(Instance);
|
||||
|
||||
impl MetadataTools {
|
||||
pub(crate) fn new() -> Result<Self, Error> {
|
||||
let meta_data_tools =
|
||||
jvm().create_instance("loci.formats.MetadataTools", InvocationArg::empty())?;
|
||||
Ok(MetadataTools(meta_data_tools))
|
||||
}
|
||||
|
||||
method!(create_ome_xml_metadata, "createOMEXMLMetadata" => Instance);
|
||||
}
|
||||
|
||||
/// Reader interface to file. Use get_frame to get data.
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct BioFormatsJavaReader {
|
||||
#[serde(skip)]
|
||||
reader: ThreadLocal<ImageReader>,
|
||||
/// path to file
|
||||
path: PathBuf,
|
||||
/// which (if more than 1) of the series in the file to open
|
||||
series: usize,
|
||||
shape: Shape,
|
||||
pixel_type: PixelType,
|
||||
little_endian: bool,
|
||||
}
|
||||
|
||||
impl From<BioFormatsJavaReader> for DynReader {
|
||||
fn from(value: BioFormatsJavaReader) -> Self {
|
||||
DynReader::BioFormatsJava(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for BioFormatsJavaReader {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.path.hash(state);
|
||||
self.series.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for BioFormatsJavaReader {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.path == other.path
|
||||
&& self.series == other.series
|
||||
&& self.shape == other.shape
|
||||
&& self.pixel_type == other.pixel_type
|
||||
&& self.little_endian == other.little_endian
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for BioFormatsJavaReader {}
|
||||
|
||||
impl Deref for BioFormatsJavaReader {
|
||||
type Target = ImageReader;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.get_reader().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for BioFormatsJavaReader {
|
||||
fn clone(&self) -> Self {
|
||||
// BioFormatsReader::new(&self.path, self.series, 0).unwrap()
|
||||
Self {
|
||||
reader: ThreadLocal::default(),
|
||||
path: self.path.clone(),
|
||||
series: self.series,
|
||||
shape: self.shape.clone(),
|
||||
pixel_type: self.pixel_type,
|
||||
little_endian: self.little_endian,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for BioFormatsJavaReader {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("BioFormatsJavaReader")
|
||||
.field("path", &self.path)
|
||||
.field("series", &self.series)
|
||||
.field("shape", &self.shape)
|
||||
.field("pixel_type", &self.pixel_type)
|
||||
.field("little_endian", &self.little_endian)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl BioFormatsJavaReader {
|
||||
fn get_reader(&self) -> Result<&ImageReader, Error> {
|
||||
self.reader.get_or_try(|| {
|
||||
let reader = ImageReader::new()?;
|
||||
let meta_data_tools = MetadataTools::new()?;
|
||||
let ome_meta = meta_data_tools.create_ome_xml_metadata()?;
|
||||
reader.set_metadata_store(ome_meta)?;
|
||||
reader.set_id(self.path.to_str().ok_or(Error::InvalidFileName)?)?;
|
||||
reader.set_series(self.series as i32)?;
|
||||
Ok(reader)
|
||||
})
|
||||
}
|
||||
|
||||
// pub fn set_reader(&self) -> Result<(), Error> {
|
||||
// self.get_reader().map(|_| ())
|
||||
// }
|
||||
|
||||
/// Get ome metadata as ome structure
|
||||
pub fn get_ome(&self) -> Result<Ome, Error> {
|
||||
let mut ome = Ome::from_xml(self.ome_xml()?)?;
|
||||
if ome.image.len() > 1 {
|
||||
ome.image = vec![ome.image[self.series].clone()];
|
||||
}
|
||||
Ok(ome)
|
||||
}
|
||||
|
||||
/// Get ome metadata as xml string
|
||||
pub fn get_ome_xml(&self) -> Result<String, Error> {
|
||||
self.ome_xml()
|
||||
}
|
||||
|
||||
fn deinterleave(&self, bytes: Vec<u8>, channel: usize) -> Result<Vec<u8>, Error> {
|
||||
let chunk_size = match self.pixel_type {
|
||||
PixelType::I8 => 1,
|
||||
PixelType::U8 => 1,
|
||||
PixelType::I16 => 2,
|
||||
PixelType::U16 => 2,
|
||||
PixelType::I32 => 4,
|
||||
PixelType::U32 => 4,
|
||||
PixelType::F32 => 4,
|
||||
PixelType::F64 => 8,
|
||||
PixelType::I64 => 8,
|
||||
PixelType::U64 => 8,
|
||||
PixelType::I128 => 16,
|
||||
PixelType::U128 => 16,
|
||||
PixelType::F128 => 8,
|
||||
};
|
||||
Ok(bytes
|
||||
.chunks(chunk_size)
|
||||
.skip(channel)
|
||||
.step_by(self.shape.c)
|
||||
.flat_map(|a| a.to_vec())
|
||||
.collect())
|
||||
}
|
||||
|
||||
fn bytes_to_frame(&self, bytes: Vec<u8>) -> Result<Frame, Error> {
|
||||
macro_rules! get_frame {
|
||||
($t:tt, <$n:expr) => {
|
||||
Ok(ArrayT::from(Array2::from_shape_vec(
|
||||
(self.shape.y, self.shape.x),
|
||||
bytes
|
||||
.chunks($n)
|
||||
.map(|x| $t::from_le_bytes(x.try_into().unwrap()))
|
||||
.collect(),
|
||||
)?))
|
||||
};
|
||||
($t:tt, >$n:expr) => {
|
||||
Ok(ArrayT::from(Array2::from_shape_vec(
|
||||
(self.shape.y, self.shape.x),
|
||||
bytes
|
||||
.chunks($n)
|
||||
.map(|x| $t::from_be_bytes(x.try_into().unwrap()))
|
||||
.collect(),
|
||||
)?))
|
||||
};
|
||||
}
|
||||
|
||||
match (&self.pixel_type, self.little_endian) {
|
||||
(PixelType::I8, true) => get_frame!(i8, <1),
|
||||
(PixelType::U8, true) => get_frame!(u8, <1),
|
||||
(PixelType::I16, true) => get_frame!(i16, <2),
|
||||
(PixelType::U16, true) => get_frame!(u16, <2),
|
||||
(PixelType::I32, true) => get_frame!(i32, <4),
|
||||
(PixelType::U32, true) => get_frame!(u32, <4),
|
||||
(PixelType::F32, true) => get_frame!(f32, <4),
|
||||
(PixelType::F64, true) => get_frame!(f64, <8),
|
||||
(PixelType::I64, true) => get_frame!(i64, <8),
|
||||
(PixelType::U64, true) => get_frame!(u64, <8),
|
||||
(PixelType::I128, true) => get_frame!(i128, <16),
|
||||
(PixelType::U128, true) => get_frame!(u128, <16),
|
||||
(PixelType::F128, true) => get_frame!(f64, <8),
|
||||
(PixelType::I8, false) => get_frame!(i8, >1),
|
||||
(PixelType::U8, false) => get_frame!(u8, >1),
|
||||
(PixelType::I16, false) => get_frame!(i16, >2),
|
||||
(PixelType::U16, false) => get_frame!(u16, >2),
|
||||
(PixelType::I32, false) => get_frame!(i32, >4),
|
||||
(PixelType::U32, false) => get_frame!(u32, >4),
|
||||
(PixelType::F32, false) => get_frame!(f32, >4),
|
||||
(PixelType::F64, false) => get_frame!(f64, >8),
|
||||
(PixelType::I64, false) => get_frame!(i64, >8),
|
||||
(PixelType::U64, false) => get_frame!(u64, >8),
|
||||
(PixelType::I128, false) => get_frame!(i128, >16),
|
||||
(PixelType::U128, false) => get_frame!(u128, >16),
|
||||
(PixelType::F128, false) => get_frame!(f64, >8),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for BioFormatsJavaReader {
|
||||
fn drop(&mut self) {
|
||||
if let Ok(reader) = self.get_reader() {
|
||||
reader.close().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Reader for BioFormatsJavaReader {
|
||||
/// Create a new reader for the image file at a path, and open series #.
|
||||
fn new<P>(path: P, series: usize, _position: usize) -> Result<Self, Error>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
DebugTools::set_root_level("ERROR")?;
|
||||
let mut path = path.as_ref().to_path_buf();
|
||||
if path.is_dir() {
|
||||
for file in path.read_dir()?.flatten() {
|
||||
let p = file.path();
|
||||
if file.path().is_file() && (p.extension() == Some("tif".as_ref())) {
|
||||
path = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut new = BioFormatsJavaReader {
|
||||
reader: ThreadLocal::default(),
|
||||
path,
|
||||
series,
|
||||
shape: Shape::default(),
|
||||
pixel_type: PixelType::I8,
|
||||
little_endian: false,
|
||||
};
|
||||
// new.set_reader()?;
|
||||
new.shape.x = new.get_size_x()? as usize;
|
||||
new.shape.y = new.get_size_y()? as usize;
|
||||
new.shape.c = new.get_size_c()? as usize;
|
||||
new.shape.z = new.get_size_z()? as usize;
|
||||
new.shape.t = new.get_size_t()? as usize;
|
||||
new.pixel_type = PixelType::try_from(new.get_pixel_type()?)?;
|
||||
new.little_endian = new.is_little_endian()?;
|
||||
Ok(new)
|
||||
}
|
||||
|
||||
fn metadata(&self) -> Result<Ome, Error> {
|
||||
self.get_ome()
|
||||
}
|
||||
|
||||
/// Retrieve fame at channel c, slize z and time t.
|
||||
fn get_frame(&self, c: usize, z: usize, t: usize) -> Result<Frame, Error> {
|
||||
let bytes = if self.is_rgb()? && self.is_interleaved()? {
|
||||
let index = self.get_index(z as i32, 0, t as i32)?;
|
||||
self.deinterleave(self.open_bytes(index)?, c)?
|
||||
} else if self.get_rgb_channel_count()? > 1 {
|
||||
let channel_separator = ChannelSeparator::new(self)?;
|
||||
let index = channel_separator.get_index(z as i32, c as i32, t as i32)?;
|
||||
channel_separator.open_bytes(index)?
|
||||
} else {
|
||||
let index = self.get_index(z as i32, c as i32, t as i32)?;
|
||||
self.open_bytes(index)?
|
||||
};
|
||||
self.bytes_to_frame(bytes)
|
||||
}
|
||||
|
||||
fn path(&self) -> &Path {
|
||||
&self.path
|
||||
}
|
||||
|
||||
fn series(&self) -> usize {
|
||||
self.series
|
||||
}
|
||||
|
||||
fn position(&self) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
fn shape(&self) -> &Shape {
|
||||
&self.shape
|
||||
}
|
||||
|
||||
fn pixel_type(&self) -> &PixelType {
|
||||
&self.pixel_type
|
||||
}
|
||||
|
||||
fn get_available_positions<P>(_path: P, _series: usize) -> Result<HashSet<usize>, Error>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
Ok(HashSet::from([0]))
|
||||
}
|
||||
|
||||
fn get_available_series<P>(path: P) -> Result<HashSet<usize>, Error>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
DebugTools::set_root_level("ERROR")?;
|
||||
let new = BioFormatsJavaReader {
|
||||
reader: ThreadLocal::default(),
|
||||
path: path.as_ref().to_path_buf(),
|
||||
series: 0,
|
||||
shape: Shape::default(),
|
||||
pixel_type: PixelType::I8,
|
||||
little_endian: false,
|
||||
};
|
||||
Ok(HashSet::from_iter(0..(new.get_series_count()? as usize)))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn open(file: &str) -> Result<BioFormatsJavaReader, Error> {
|
||||
let path = std::env::current_dir()?
|
||||
.join("tests")
|
||||
.join("files")
|
||||
.join(file);
|
||||
BioFormatsJavaReader::new(&path, 0, 0)
|
||||
}
|
||||
|
||||
macro_rules! test_metadata {
|
||||
($($name:ident: $file:expr $(,)?)*) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $name() -> Result<(), Error> {
|
||||
let bf = open($file)?;
|
||||
println!("{}", bf.view().squeeze()?.summary()?);
|
||||
Ok(())
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
test_metadata! {
|
||||
metadata_a: "czi/1xp53-01-AP1.czi",
|
||||
metadata_b: "czi/beads_2023_05_04__19_00_22.czi",
|
||||
metadata_c: "czi/Experiment-2029.czi",
|
||||
metadata_d: "czi/MK022_cE9_1-01-Airyscan Processing-01-Scene-2-P1.czi",
|
||||
metadata_e: "czi/YTL1849A131_2023_05_04__13_36_36.czi",
|
||||
metadata_f: "czi/EU_UV_t=1-01.czi",
|
||||
metadata_g: "tiffseq/4-Pos_001_002/img_000000000_Cy3-Cy3_filter_000.tif",
|
||||
metadata_h: "tiffseq/20-Pos_005_005/img_000000000_Cy3-Cy3_filter_000.tif"
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ome_xml() -> Result<(), Error> {
|
||||
let file = "czi/Experiment-2029.czi";
|
||||
let path = std::env::current_dir()?
|
||||
.join("tests")
|
||||
.join("files")
|
||||
.join(file);
|
||||
let reader = BioFormatsJavaReader::new(&path, 0, 0)?;
|
||||
let xml = reader.get_ome_xml()?;
|
||||
println!("{}", xml);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user