- change to MIT license
- thread local image reader instances - add keywords and categories - add python dependencies - README
This commit is contained in:
@@ -71,6 +71,7 @@ macro_rules! method_arg {
|
||||
|
||||
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)?;
|
||||
@@ -95,10 +96,12 @@ macro_rules! method {
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) struct DebugTools;
|
||||
/// Wrapper around bioformats java class loci.common.DebugTools
|
||||
pub struct DebugTools;
|
||||
|
||||
impl DebugTools {
|
||||
pub(crate) fn set_root_level(level: &str) -> Result<()> {
|
||||
/// set debug root level: ERROR, DEBUG, TRACE, INFO, OFF
|
||||
pub fn set_root_level(level: &str) -> Result<()> {
|
||||
jvm().invoke_static(
|
||||
"loci.common.DebugTools",
|
||||
"setRootLevel",
|
||||
@@ -108,6 +111,7 @@ impl DebugTools {
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper around bioformats java class loci.formats.ChannelSeparator
|
||||
pub(crate) struct ChannelSeparator(Instance);
|
||||
|
||||
impl ChannelSeparator {
|
||||
@@ -129,7 +133,8 @@ impl ChannelSeparator {
|
||||
method!(get_index, "getIndex", [z: i32|p, c: i32|p, t: i32|p] => i32|c);
|
||||
}
|
||||
|
||||
pub(crate) struct ImageReader(Instance);
|
||||
/// Wrapper around bioformats java class loci.formats.ImageReader
|
||||
pub struct ImageReader(Instance);
|
||||
|
||||
impl Drop for ImageReader {
|
||||
fn drop(&mut self) {
|
||||
@@ -179,6 +184,7 @@ impl ImageReader {
|
||||
method!(close, "close");
|
||||
}
|
||||
|
||||
/// Wrapper around bioformats java class loci.formats.MetadataTools
|
||||
pub(crate) struct MetadataTools(Instance);
|
||||
|
||||
impl MetadataTools {
|
||||
|
||||
83
src/lib.rs
83
src/lib.rs
@@ -9,7 +9,9 @@ use ndarray::Array2;
|
||||
use num::{FromPrimitive, Zero};
|
||||
use std::any::type_name;
|
||||
use std::fmt::Debug;
|
||||
use std::ops::Deref;
|
||||
use std::path::{Path, PathBuf};
|
||||
use thread_local::ThreadLocal;
|
||||
|
||||
/// Pixel types (u)int(8/16/32) or float(32/64)
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -141,7 +143,7 @@ where
|
||||
|
||||
/// Reader interface to file. Use get_frame to get data.
|
||||
pub struct Reader {
|
||||
image_reader: ImageReader,
|
||||
image_reader: ThreadLocal<ImageReader>,
|
||||
/// path to file
|
||||
pub path: PathBuf,
|
||||
/// which (if more than 1) of the series in the file to open
|
||||
@@ -161,6 +163,22 @@ pub struct Reader {
|
||||
little_endian: bool,
|
||||
}
|
||||
|
||||
impl Deref for Reader {
|
||||
type Target = ImageReader;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.image_reader.get_or(|| {
|
||||
let reader = ImageReader::new().unwrap();
|
||||
let meta_data_tools = MetadataTools::new().unwrap();
|
||||
let ome_meta = meta_data_tools.create_ome_xml_metadata().unwrap();
|
||||
reader.set_metadata_store(ome_meta).unwrap();
|
||||
reader.set_id(self.path.to_str().unwrap()).unwrap();
|
||||
reader.set_series(self.series).unwrap();
|
||||
reader
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Reader {
|
||||
fn clone(&self) -> Self {
|
||||
Reader::new(&self.path, self.series).unwrap()
|
||||
@@ -187,36 +205,31 @@ impl Reader {
|
||||
/// Create new reader for image file at path.
|
||||
pub fn new(path: &Path, series: i32) -> Result<Self> {
|
||||
DebugTools::set_root_level("ERROR")?;
|
||||
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(path.to_str().unwrap())?;
|
||||
reader.set_series(series)?;
|
||||
let size_x = reader.get_size_x()?;
|
||||
let size_y = reader.get_size_y()?;
|
||||
let size_c = reader.get_size_c()?;
|
||||
let size_z = reader.get_size_z()?;
|
||||
let size_t = reader.get_size_t()?;
|
||||
let pixel_type = PixelType::try_from(reader.get_pixel_type()?)?;
|
||||
let little_endian = reader.is_little_endian()?;
|
||||
Ok(Reader {
|
||||
image_reader: reader,
|
||||
let mut reader = Reader {
|
||||
image_reader: ThreadLocal::new(),
|
||||
path: PathBuf::from(path),
|
||||
series,
|
||||
size_x: size_x as usize,
|
||||
size_y: size_y as usize,
|
||||
size_c: size_c as usize,
|
||||
size_z: size_z as usize,
|
||||
size_t: size_t as usize,
|
||||
pixel_type,
|
||||
little_endian,
|
||||
})
|
||||
size_x: 0,
|
||||
size_y: 0,
|
||||
size_c: 0,
|
||||
size_z: 0,
|
||||
size_t: 0,
|
||||
pixel_type: PixelType::INT8,
|
||||
little_endian: false,
|
||||
};
|
||||
reader.size_x = reader.get_size_x()? as usize;
|
||||
reader.size_y = reader.get_size_y()? as usize;
|
||||
reader.size_c = reader.get_size_c()? as usize;
|
||||
reader.size_z = reader.get_size_z()? as usize;
|
||||
reader.size_t = reader.get_size_t()? as usize;
|
||||
reader.pixel_type = PixelType::try_from(reader.get_pixel_type()?)?;
|
||||
reader.little_endian = reader.is_little_endian()?;
|
||||
Ok(reader)
|
||||
}
|
||||
|
||||
/// Get ome metadata as xml string
|
||||
pub fn get_ome_xml(&self) -> Result<String> {
|
||||
self.image_reader.ome_xml()
|
||||
self.ome_xml()
|
||||
}
|
||||
|
||||
fn deinterleave(&self, bytes: Vec<u8>, channel: usize) -> Result<Vec<u8>> {
|
||||
@@ -240,16 +253,16 @@ impl Reader {
|
||||
|
||||
/// Retrieve fame at channel c, slize z and time t.
|
||||
pub fn get_frame(&self, c: usize, z: usize, t: usize) -> Result<Frame> {
|
||||
let bytes = if self.image_reader.is_rgb()? & self.image_reader.is_interleaved()? {
|
||||
let index = self.image_reader.get_index(z as i32, 0, t as i32)?;
|
||||
self.deinterleave(self.image_reader.open_bytes(index)?, c)?
|
||||
} else if self.image_reader.get_rgb_channel_count()? > 1 {
|
||||
let channel_separator = bioformats::ChannelSeparator::new(&self.image_reader)?;
|
||||
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 = bioformats::ChannelSeparator::new(self)?;
|
||||
let index = channel_separator.get_index(z as i32, c as i32, t as i32)?;
|
||||
channel_separator.open_bytes(index)?
|
||||
} else if self.image_reader.is_indexed()? {
|
||||
let index = self.image_reader.get_index(z as i32, 0, t as i32)?;
|
||||
self.image_reader.open_bytes(index)?
|
||||
} else if self.is_indexed()? {
|
||||
let index = self.get_index(z as i32, 0, t as i32)?;
|
||||
self.open_bytes(index)?
|
||||
// TODO: apply LUT
|
||||
// let _bytes_lut = match self.pixel_type {
|
||||
// PixelType::INT8 | PixelType::UINT8 => {
|
||||
@@ -261,8 +274,8 @@ impl Reader {
|
||||
// _ => {}
|
||||
// };
|
||||
} else {
|
||||
let index = self.image_reader.get_index(z as i32, c as i32, t as i32)?;
|
||||
self.image_reader.open_bytes(index)?
|
||||
let index = self.get_index(z as i32, c as i32, t as i32)?;
|
||||
self.open_bytes(index)?
|
||||
};
|
||||
self.bytes_to_frame(bytes)
|
||||
}
|
||||
|
||||
13
src/py.rs
13
src/py.rs
@@ -8,17 +8,16 @@ use std::path::PathBuf;
|
||||
#[pyo3(name = "Reader")]
|
||||
#[derive(Debug)]
|
||||
struct PyReader {
|
||||
path: PathBuf,
|
||||
series: i32,
|
||||
reader: Reader,
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PyReader {
|
||||
#[new]
|
||||
fn new(path: &str, series: usize) -> PyResult<Self> {
|
||||
let path = PathBuf::from(path);
|
||||
Ok(PyReader {
|
||||
path: PathBuf::from(path),
|
||||
series: series as i32,
|
||||
reader: Reader::new(&path, series as i32)?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -29,8 +28,7 @@ impl PyReader {
|
||||
z: usize,
|
||||
t: usize,
|
||||
) -> PyResult<Bound<'py, PyAny>> {
|
||||
let reader = Reader::new(&self.path, self.series)?; // TODO: prevent making a new Reader each time
|
||||
Ok(match reader.get_frame(c, z, t)? {
|
||||
Ok(match self.reader.get_frame(c, z, t)? {
|
||||
Frame::INT8(arr) => arr.to_pyarray(py).into_any(),
|
||||
Frame::UINT8(arr) => arr.to_pyarray(py).into_any(),
|
||||
Frame::INT16(arr) => arr.to_pyarray(py).into_any(),
|
||||
@@ -43,8 +41,7 @@ impl PyReader {
|
||||
}
|
||||
|
||||
fn get_ome_xml(&self) -> PyResult<String> {
|
||||
let reader = Reader::new(&self.path, self.series)?; // TODO: prevent making a new Reader each time
|
||||
Ok(reader.get_ome_xml()?)
|
||||
Ok(self.reader.get_ome_xml()?)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user