231 lines
7.2 KiB
Rust
231 lines
7.2 KiB
Rust
use crate::error::Error;
|
|
use j4rs::{Instance, InvocationArg, Jvm, JvmBuilder};
|
|
use std::cell::OnceCell;
|
|
use std::rc::Rc;
|
|
|
|
thread_local! {
|
|
static JVM: OnceCell<Rc<Jvm>> = const { OnceCell::new() }
|
|
}
|
|
|
|
/// 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()
|
|
};
|
|
if !class_path.join("jassets").exists() {
|
|
panic!(
|
|
"jassets directory does not exist in {}",
|
|
class_path.display()
|
|
);
|
|
}
|
|
|
|
Rc::new(
|
|
JvmBuilder::new()
|
|
.skip_setting_native_lib()
|
|
.with_base_path(class_path.to_str().unwrap())
|
|
.build()
|
|
.expect("Failed to build JVM"),
|
|
)
|
|
})
|
|
.clone()
|
|
})
|
|
}
|
|
|
|
pub fn download_bioformats(gpl_formats: bool) -> Result<(), Error> {
|
|
#[cfg(feature = "python")]
|
|
let path = crate::py::ndbioimage_file();
|
|
|
|
#[cfg(not(feature = "python"))]
|
|
let path = std::env::current_exe()?.parent().unwrap().to_path_buf();
|
|
|
|
let class_path = path.parent().unwrap();
|
|
let jassets = class_path.join("jassets");
|
|
if !jassets.exists() {
|
|
std::fs::create_dir_all(jassets)?;
|
|
}
|
|
println!("installing jassets in {}", class_path.display());
|
|
let jvm = JvmBuilder::new()
|
|
.skip_setting_native_lib()
|
|
.with_base_path(class_path.to_str().unwrap())
|
|
.with_maven_settings(j4rs::MavenSettings::new(vec![
|
|
j4rs::MavenArtifactRepo::from(
|
|
"openmicroscopy::https://artifacts.openmicroscopy.org/artifactory/ome.releases",
|
|
),
|
|
]))
|
|
.build()?;
|
|
|
|
jvm.deploy_artifact(&j4rs::MavenArtifact::from("ome:bioformats_package:8.3.0"))?;
|
|
|
|
if gpl_formats {
|
|
jvm.deploy_artifact(&j4rs::MavenArtifact::from("ome:formats-gpl:8.3.0"))?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
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!(set_metadata_store, "setMetadataStore", [ome_data: Instance]);
|
|
method!(get_metadata_store, "getMetadataStore" => Instance);
|
|
method!(set_id, "setId", [id: &str]);
|
|
method!(set_series, "setSeries", [series: i32|p]);
|
|
method!(open_bi8, "openBytes", [index: i32|p] => Vec<i8>|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!(get_pixel_type, "getPixelType" => i32|c);
|
|
method!(is_little_endian, "isLittleEndian" => bool|c);
|
|
method!(is_rgb, "isRGB" => bool|c);
|
|
method!(is_interleaved, "isInterleaved" => bool|c);
|
|
method!(get_index, "getIndex", [z: i32|p, c: i32|p, t: i32|p] => i32|c);
|
|
method!(get_rgb_channel_count, "getRGBChannelCount" => i32|c);
|
|
method!(is_indexed, "isIndexed" => bool|c);
|
|
method!(get_8bit_lookup_table, "get8BitLookupTable" => Instance);
|
|
method!(get_16bit_lookup_table, "get16BitLookupTable" => Instance);
|
|
method!(close, "close");
|
|
}
|
|
|
|
/// 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);
|
|
}
|