some more test and fixes to get them working
This commit is contained in:
4
.github/workflows/publish.yml
vendored
4
.github/workflows/publish.yml
vendored
@@ -11,7 +11,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 25
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
submodules: 'true'
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: cargo-release Cache
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "libczirw-sys"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
edition = "2024"
|
||||
rust-version = "1.85.1"
|
||||
authors = ["Wim Pomp <w.pomp@nki.nl>"]
|
||||
|
||||
20
build.rs
20
build.rs
@@ -83,40 +83,40 @@ fn main() -> Result<()> {
|
||||
#[cfg(not(feature = "dynamic"))]
|
||||
{
|
||||
println!(
|
||||
"cargo:rustc-link-search=native={}",
|
||||
"cargo::rustc-link-search=native={}",
|
||||
dst.join("build/Src/libCZIAPI").display()
|
||||
);
|
||||
println!("cargo:rustc-link-lib=static=libCZIAPIStatic");
|
||||
println!("cargo::rustc-link-lib=static=libCZIAPIStatic");
|
||||
|
||||
println!(
|
||||
"cargo:rustc-link-search=native={}",
|
||||
"cargo::rustc-link-search=native={}",
|
||||
dst.join("build/Src/libCZI").display()
|
||||
);
|
||||
let profile = env::var("PROFILE")?;
|
||||
match profile.as_str() {
|
||||
"debug" => println!("cargo:rustc-link-lib=static=libCZIStaticd"),
|
||||
"release" => println!("cargo:rustc-link-lib=static=libCZIStatic"),
|
||||
"debug" => println!("cargo::rustc-link-lib=static=libCZIStaticd"),
|
||||
"release" => println!("cargo::rustc-link-lib=static=libCZIStatic"),
|
||||
_ => return Err(Error::msg(format!("unsupported profile: {}", profile))),
|
||||
}
|
||||
|
||||
println!(
|
||||
"cargo:rustc-link-search=native={}",
|
||||
"cargo::rustc-link-search=native={}",
|
||||
dst.join("lib").display()
|
||||
);
|
||||
println!(
|
||||
"cargo:rustc-link-search=native={}",
|
||||
"cargo::rustc-link-search=native={}",
|
||||
dst.join("lib64").display()
|
||||
);
|
||||
println!("cargo:rustc-link-lib=static=zstd");
|
||||
println!("cargo::rustc-link-lib=static=zstd");
|
||||
}
|
||||
|
||||
#[cfg(feature = "dynamic")]
|
||||
{
|
||||
println!(
|
||||
"cargo:rustc-link-search=native={}",
|
||||
"cargo::rustc-link-search=native={}",
|
||||
dst.join("build/Src/libCZIAPI").display()
|
||||
);
|
||||
println!("cargo:rustc-link-lib=libCZIAPI");
|
||||
println!("cargo::rustc-link-lib=libCZIAPI");
|
||||
}
|
||||
}
|
||||
println!("cargo::rerun-if-changed=build.rs");
|
||||
|
||||
@@ -196,7 +196,10 @@ impl CziReader {
|
||||
libCZI_ReaderGetPyramidStatistics(**self, ptr.as_mut_ptr())
|
||||
})?;
|
||||
let ptr = unsafe { ptr.assume_init() };
|
||||
let statistics = unsafe { CStr::from_ptr(ptr) }.to_str()?.to_owned();
|
||||
assert!(!ptr.is_null());
|
||||
let statistics = unsafe { CStr::from_ptr(ptr) }
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
unsafe { libCZI_Free(ptr as *mut c_void) };
|
||||
Ok(statistics)
|
||||
}
|
||||
@@ -653,7 +656,7 @@ impl LockedBitmap {
|
||||
***self,
|
||||
width,
|
||||
height,
|
||||
pixel_type.into(),
|
||||
pixel_type as i32,
|
||||
stride,
|
||||
data.as_mut_ptr() as *mut c_void,
|
||||
)
|
||||
@@ -733,7 +736,10 @@ impl CziDocumentInfo {
|
||||
)
|
||||
})?;
|
||||
let ptr = unsafe { ptr.assume_init() };
|
||||
let info = unsafe { CStr::from_ptr(ptr) }.to_str()?.to_owned();
|
||||
assert!(!ptr.is_null());
|
||||
let info = unsafe { CStr::from_ptr(ptr) }
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
unsafe { libCZI_Free(ptr as *mut c_void) };
|
||||
Ok(info)
|
||||
}
|
||||
@@ -782,9 +788,10 @@ impl CziDocumentInfo {
|
||||
)
|
||||
})?;
|
||||
let ptr = unsafe { ptr.assume_init() };
|
||||
let info = unsafe { CStr::from_ptr(ptr) }.to_str()?.to_owned();
|
||||
unsafe { libCZI_Free(ptr as *mut c_void) };
|
||||
Ok(info)
|
||||
assert!(!ptr.is_null());
|
||||
Ok(unsafe { CStr::from_ptr(ptr) }
|
||||
.to_string_lossy()
|
||||
.into_owned())
|
||||
}
|
||||
|
||||
/// Release the specified CZI-document-info object.
|
||||
|
||||
@@ -3,6 +3,8 @@ use crate::misc::{PixelType, Ptr};
|
||||
use crate::sys::*;
|
||||
use anyhow::{Error, Result};
|
||||
use std::ffi::{CStr, CString, c_char, c_void};
|
||||
use std::fmt::Debug;
|
||||
use std::mem;
|
||||
use std::mem::{ManuallyDrop, MaybeUninit};
|
||||
|
||||
/// This struct contains the version information of the libCZIApi-library. For versioning libCZI, SemVer2 (<https://semver.org/>) is used.
|
||||
@@ -597,7 +599,7 @@ impl BitmapInfo {
|
||||
Self(BitmapInfoInterop {
|
||||
width,
|
||||
height,
|
||||
pixelType: pixel_type.into(),
|
||||
pixelType: pixel_type as i32,
|
||||
})
|
||||
}
|
||||
pub fn get_width(&self) -> u32 {
|
||||
@@ -616,19 +618,22 @@ impl BitmapInfo {
|
||||
self.0.height = height;
|
||||
}
|
||||
pub fn set_pixel_type(&mut self, pixel_type: PixelType) {
|
||||
self.0.pixelType = pixel_type.into();
|
||||
self.0.pixelType = pixel_type as i32;
|
||||
}
|
||||
}
|
||||
|
||||
impl BitmapLockInfo {
|
||||
pub fn get_data_roi(&self) -> Vec<u8> {
|
||||
unsafe {
|
||||
let vec = unsafe {
|
||||
Vec::from_raw_parts(
|
||||
self.0.ptrDataRoi as *mut u8,
|
||||
self.0.size as usize,
|
||||
self.0.size as usize,
|
||||
)
|
||||
}
|
||||
};
|
||||
let res = vec.clone();
|
||||
mem::forget(vec);
|
||||
res
|
||||
}
|
||||
|
||||
pub fn get_stride(&self) -> u32 {
|
||||
@@ -651,7 +656,7 @@ impl SubBlockInfo {
|
||||
) -> Self {
|
||||
Self(SubBlockInfoInterop {
|
||||
compression_mode_raw,
|
||||
pixel_type: pixel_type.into(),
|
||||
pixel_type: pixel_type as i32,
|
||||
coordinate: coordinate.0,
|
||||
logical_rect: logical_rect.0,
|
||||
physical_size: physical_size.0,
|
||||
@@ -680,7 +685,7 @@ impl SubBlockInfo {
|
||||
self.0.compression_mode_raw = compression_mode_raw
|
||||
}
|
||||
pub fn set_pixel_type(&mut self, pixel_type: PixelType) {
|
||||
self.0.pixel_type = pixel_type.into();
|
||||
self.0.pixel_type = pixel_type as i32;
|
||||
}
|
||||
pub fn set_coordinate(&mut self, coordinate: Coordinate) {
|
||||
self.0.coordinate = coordinate.0
|
||||
@@ -790,7 +795,7 @@ impl AddSubBlockInfo {
|
||||
logical_height,
|
||||
physical_width,
|
||||
physical_height,
|
||||
pixel_type: pixel_type.into(),
|
||||
pixel_type: pixel_type as i32,
|
||||
compression_mode_raw,
|
||||
size_data: data.len() as u32,
|
||||
data: data.as_ptr() as *const c_void,
|
||||
@@ -898,7 +903,7 @@ impl AddSubBlockInfo {
|
||||
self.0.physical_height = physical_height
|
||||
}
|
||||
pub fn set_pixel_type(&mut self, pixel_type: PixelType) {
|
||||
self.0.pixel_type = pixel_type.into()
|
||||
self.0.pixel_type = pixel_type as i32
|
||||
}
|
||||
pub fn set_compression_mode_raw(&mut self, compression_mode_raw: i32) {
|
||||
self.0.compression_mode_raw = compression_mode_raw
|
||||
|
||||
57
src/lib.rs
57
src/lib.rs
@@ -9,16 +9,71 @@ pub mod sys;
|
||||
pub use functions::*;
|
||||
pub use handle::*;
|
||||
pub use interop::*;
|
||||
pub use misc::{LibCZIApiError, PixelType, RawDataType};
|
||||
pub use misc::{Dimension, LibCZIApiError, PixelType, RawDataType};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::handle::{CziReader, InputStream};
|
||||
use crate::interop::{LibCZIBuildInformation, ReaderOpenInfo};
|
||||
use crate::misc::Dimension;
|
||||
use anyhow::{Error, Result};
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[test]
|
||||
fn test_read_shape() -> Result<()> {
|
||||
let path = env::home_dir()
|
||||
.unwrap()
|
||||
.join("code/rust/ndbioimage/tests/files/Experiment-2029.czi");
|
||||
assert!(path.exists());
|
||||
let czi = CziReader::create()?;
|
||||
let stream = InputStream::create_from_file_utf8(
|
||||
path.to_str().ok_or(Error::msg("cannot into str"))?,
|
||||
)?;
|
||||
let open_info = ReaderOpenInfo::new(&stream);
|
||||
czi.open(open_info)?;
|
||||
println!("pyramid statistics: {:?}", czi.get_pyramid_statistics()?);
|
||||
println!("file header info: {:?}", czi.get_file_header_info()?);
|
||||
let statistics_simple = czi.get_statistics_simple()?;
|
||||
println!("statistics simple: {:?}", czi.get_statistics_simple()?);
|
||||
let bounding_box = statistics_simple.get_bounding_box();
|
||||
let dim_bounds = statistics_simple.get_dim_bounds();
|
||||
let dimensions = Dimension::vec_from_bitflags(dim_bounds.get_dimensions_valid());
|
||||
let size = dim_bounds.get_size();
|
||||
for (i, d) in dimensions.iter().enumerate() {
|
||||
println!("{:?}: {}", d, size[i]);
|
||||
}
|
||||
println!("X: {}", bounding_box.get_w());
|
||||
println!("Y: {}", bounding_box.get_h());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_bytes() -> Result<()> {
|
||||
let path = env::home_dir()
|
||||
.unwrap()
|
||||
.join("code/rust/ndbioimage/tests/files/Experiment-2029.czi");
|
||||
assert!(path.exists());
|
||||
let czi = CziReader::create()?;
|
||||
let stream = InputStream::create_from_file_utf8(
|
||||
path.to_str().ok_or(Error::msg("cannot into str"))?,
|
||||
)?;
|
||||
let open_info = ReaderOpenInfo::new(&stream);
|
||||
czi.open(open_info)?;
|
||||
let sub_block = czi.read_sub_block(0)?;
|
||||
let bitmap = sub_block.create_bitmap()?.lock()?;
|
||||
let bitmap_info = bitmap.get_info()?;
|
||||
println!(
|
||||
"height: {}, width: {} pixel type: {:#?}",
|
||||
bitmap_info.get_height(),
|
||||
bitmap_info.get_width(),
|
||||
bitmap_info.get_pixel_type()?
|
||||
);
|
||||
let bytes = bitmap.lock_info.get_data_roi();
|
||||
println!("bytes: {:?}", bytes.as_slice()[..100].to_vec());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_libczi_xml() -> Result<()> {
|
||||
let path = env::home_dir()
|
||||
|
||||
113
src/misc.rs
113
src/misc.rs
@@ -40,25 +40,94 @@ impl fmt::Display for LibCZIApiError {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Dimension {
|
||||
/// The Z-dimension.
|
||||
Z = 1,
|
||||
/// The C-dimension ("channel").
|
||||
C = 2,
|
||||
/// The T-dimension ("time").
|
||||
T = 3,
|
||||
/// The R-dimension ("rotation").
|
||||
R = 4,
|
||||
/// The S-dimension ("scene").
|
||||
S = 5,
|
||||
/// The I-dimension ("illumination").
|
||||
I = 6,
|
||||
/// The H-dimension ("phase").
|
||||
H = 7,
|
||||
/// The V-dimension ("view").
|
||||
V = 8,
|
||||
/// The B-dimension ("block") - its use is deprecated.
|
||||
B = 9,
|
||||
}
|
||||
|
||||
impl Dimension {
|
||||
pub fn vec_from_bitflags(bit_flags: u32) -> Vec<Dimension> {
|
||||
let mut bit_flags = bit_flags;
|
||||
let mut dimensions = Vec::with_capacity(9);
|
||||
for i in 1..=9 {
|
||||
if (bit_flags & 1) > 0 {
|
||||
dimensions.push(Dimension::try_from(i).expect("i must be 0 <= i <= 9"));
|
||||
}
|
||||
bit_flags >>= 1;
|
||||
}
|
||||
dimensions
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<i32> for Dimension {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(dimension: i32) -> Result<Self> {
|
||||
match dimension {
|
||||
1 => Ok(Dimension::Z),
|
||||
2 => Ok(Dimension::C),
|
||||
3 => Ok(Dimension::T),
|
||||
4 => Ok(Dimension::R),
|
||||
5 => Ok(Dimension::S),
|
||||
6 => Ok(Dimension::I),
|
||||
7 => Ok(Dimension::H),
|
||||
8 => Ok(Dimension::V),
|
||||
9 => Ok(Dimension::B),
|
||||
_ => Err(anyhow!("Unknown dimension value {}", dimension)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// enum for SubBlock.get_raw_data
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum RawDataType {
|
||||
Data,
|
||||
Metadata,
|
||||
Data = 0,
|
||||
Metadata = 1,
|
||||
}
|
||||
|
||||
impl TryFrom<i32> for RawDataType {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(raw_data_type: i32) -> Result<Self> {
|
||||
match raw_data_type {
|
||||
0 => Ok(RawDataType::Data),
|
||||
1 => Ok(RawDataType::Metadata),
|
||||
_ => Err(anyhow!("Unknown data type {}", raw_data_type)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// pixel type
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum PixelType {
|
||||
Gray8,
|
||||
Gray16,
|
||||
Gray32Float,
|
||||
Bgr24,
|
||||
Bgr48,
|
||||
Bgr96Float,
|
||||
Bgra32,
|
||||
Gray64ComplexFloat,
|
||||
Bgr192ComplexFloat,
|
||||
Gray32,
|
||||
Gray64Float,
|
||||
Gray8 = 0,
|
||||
Gray16 = 1,
|
||||
Gray32Float = 2,
|
||||
Bgr24 = 3,
|
||||
Bgr48 = 4,
|
||||
Bgr96Float = 8,
|
||||
Bgra32 = 9,
|
||||
Gray64ComplexFloat = 10,
|
||||
Bgr192ComplexFloat = 11,
|
||||
Gray32 = 12,
|
||||
Gray64Float = 13,
|
||||
}
|
||||
|
||||
impl TryFrom<i32> for PixelType {
|
||||
@@ -82,24 +151,6 @@ impl TryFrom<i32> for PixelType {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PixelType> for i32 {
|
||||
fn from(pixel_type: PixelType) -> Self {
|
||||
match pixel_type {
|
||||
PixelType::Gray8 => 0,
|
||||
PixelType::Gray16 => 1,
|
||||
PixelType::Gray32Float => 2,
|
||||
PixelType::Bgr24 => 3,
|
||||
PixelType::Bgr48 => 4,
|
||||
PixelType::Bgr96Float => 8,
|
||||
PixelType::Bgra32 => 9,
|
||||
PixelType::Gray64ComplexFloat => 10,
|
||||
PixelType::Bgr192ComplexFloat => 11,
|
||||
PixelType::Gray32 => 12,
|
||||
PixelType::Gray64Float => 13,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Ptr {
|
||||
type Pointer;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user