From d2c725440c601e0ce23d7b074b043399b9cdeb60 Mon Sep 17 00:00:00 2001 From: Wim Pomp Date: Sun, 4 Jan 2026 17:03:14 +0100 Subject: [PATCH] - bump ome-metadata dependency - add extract-ome cli subcommand --- Cargo.toml | 6 +++--- src/main.rs | 15 ++++++++++++- src/metadata.rs | 57 +++++++++++++++++++++---------------------------- src/reader.rs | 6 ++---- 4 files changed, 43 insertions(+), 41 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index eb6c9c7..dc51480 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ndbioimage" -version = "2026.1.1" +version = "2026.1.2" edition = "2024" rust-version = "1.85.1" authors = ["Wim Pomp "] @@ -36,7 +36,7 @@ serde_json = { version = "1", optional = true } serde_with = "3" tiffwrite = { version = "2025.12.0", optional = true} thread_local = "1" -ome-metadata = "0.3.2" +ome-metadata = "0.4" lazy_static = "1" thiserror = "2" @@ -46,8 +46,8 @@ features = ["extension-module", "abi3-py310", "generate-import-lib", "anyhow"] optional = true [dev-dependencies] -rayon = "1" downloader = "0.2" +rayon = "1" regex = "1" reqwest = { version = "0.13", features = ["blocking"] } diff --git a/src/main.rs b/src/main.rs index 76823a9..b4c7e03 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,7 @@ use ndarray::SliceInfoElem; use ndbioimage::error::Error; #[cfg(feature = "movie")] use ndbioimage::movie::MovieOptions; -use ndbioimage::reader::split_path_and_series; +use ndbioimage::reader::{split_path_and_series, Reader}; #[cfg(feature = "tiff")] use ndbioimage::tiff::TiffOptions; use ndbioimage::view::View; @@ -24,6 +24,11 @@ enum Commands { #[arg(value_name = "FILE", num_args(1..))] file: Vec, }, + /// save ome metadata as xml + ExtractOME { + #[arg(value_name = "FILE", num_args(1..))] + file: Vec, + }, /// Save the image as tiff file #[cfg(feature = "tiff")] Tiff { @@ -113,6 +118,14 @@ pub(crate) fn main() -> Result<(), Error> { println!("{}", view.summary()?); } } + Commands::ExtractOME { file } => { + for f in file { + let (path, series) = split_path_and_series(f)?; + let reader = Reader::new(&path, series.unwrap_or(0))?; + let xml = reader.get_ome_xml()?; + std::fs::write(path.with_extension("xml"), xml)?; + } + } #[cfg(feature = "tiff")] Commands::Tiff { file, diff --git a/src/metadata.rs b/src/metadata.rs index 6b0fea1..0e34489 100644 --- a/src/metadata.rs +++ b/src/metadata.rs @@ -9,18 +9,13 @@ impl Metadata for Ome { fn get_instrument(&self) -> Option<&Instrument> { let instrument_id = self.get_image()?.instrument_ref.as_ref()?.id.clone(); self.instrument - .as_ref()? .iter() .find(|i| i.id == instrument_id) } fn get_image(&self) -> Option<&Image> { - if let Some(image) = &self.image { - if !image.is_empty() { - Some(&image[0]) - } else { - None - } + if let Some(image) = &self.image.first() { + Some(&image) } else { None } @@ -130,24 +125,22 @@ pub trait Metadata { /// time interval in seconds for time-lapse images fn time_interval(&self) -> Result, Error> { if let Some(pixels) = self.get_pixels() { - if let Some(plane) = &pixels.plane { - if let Some(t) = plane.iter().map(|p| p.the_t).max() { - if t > 0 { - let plane_a = plane - .iter() - .find(|p| (p.the_c == 0) && (p.the_z == 0) && (p.the_t == 0)); - let plane_b = plane - .iter() - .find(|p| (p.the_c == 0) && (p.the_z == 0) && (p.the_t == t)); - if let (Some(a), Some(b)) = (plane_a, plane_b) { - if let (Some(a_t), Some(b_t)) = (a.delta_t, b.delta_t) { - return Ok(Some( - (b.delta_t_unit.convert(&UnitsTime::s, b_t as f64)? - - a.delta_t_unit.convert(&UnitsTime::s, a_t as f64)?) - .abs() - / (t as f64), - )); - } + if let Some(t) = pixels.plane.iter().map(|p| p.the_t).max() { + if t > 0 { + let plane_a = pixels.plane + .iter() + .find(|p| (p.the_c == 0) && (p.the_z == 0) && (p.the_t == 0)); + let plane_b = pixels.plane + .iter() + .find(|p| (p.the_c == 0) && (p.the_z == 0) && (p.the_t == t)); + if let (Some(a), Some(b)) = (plane_a, plane_b) { + if let (Some(a_t), Some(b_t)) = (a.delta_t, b.delta_t) { + return Ok(Some( + (b.delta_t_unit.convert(&UnitsTime::s, b_t as f64)? + - a.delta_t_unit.convert(&UnitsTime::s, a_t as f64)?) + .abs() + / (t as f64), + )); } } } @@ -160,14 +153,12 @@ pub trait Metadata { fn exposure_time(&self, channel: usize) -> Result, Error> { let c = channel as i32; if let Some(pixels) = self.get_pixels() { - if let Some(plane) = &pixels.plane { - if let Some(p) = plane - .iter() - .find(|p| (p.the_c == c) && (p.the_z == 0) && (p.the_t == 0)) - { - if let Some(t) = p.exposure_time { - return Ok(Some(p.exposure_time_unit.convert(&UnitsTime::s, t as f64)?)); - } + if let Some(p) = pixels.plane + .iter() + .find(|p| (p.the_c == c) && (p.the_z == 0) && (p.the_t == 0)) + { + if let Some(t) = p.exposure_time { + return Ok(Some(p.exposure_time_unit.convert(&UnitsTime::s, t as f64)?)); } } } diff --git a/src/reader.rs b/src/reader.rs index f115bab..d64bfe5 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -344,10 +344,8 @@ impl Reader { /// Get ome metadata as ome structure pub fn get_ome(&self) -> Result { let mut ome = self.ome_xml()?.parse::()?; - if let Some(image) = ome.image.as_ref() { - if image.len() > 1 { - ome.image = Some(vec![image[self.series].clone()]); - } + if ome.image.len() > 1 { + ome.image = vec![ome.image[self.series].clone()]; } Ok(ome) }