use crate::{bindings, errors::OpenSlideError, OpenSlide, Properties, Region, Result, Size};
use std::path::Path;
#[cfg(feature = "image")]
use {
crate::{
utils::{_bgra_to_rgb, _bgra_to_rgba_inplace, resize_rgb_image, resize_rgba_image},
Address,
},
image::{RgbImage, RgbaImage},
};
#[cfg(feature = "openslide4")]
use crate::cache::Cache;
impl Drop for OpenSlide {
fn drop(&mut self) {
bindings::close(*self.osr)
}
}
impl OpenSlide {
pub fn get_version() -> Result<String> {
bindings::get_version()
}
pub fn new<T: AsRef<Path>>(path: T) -> Result<OpenSlide> {
let path = path.as_ref();
if !path.exists() {
return Err(OpenSlideError::MissingFile(path.display().to_string()));
}
let filename = path.display().to_string();
let osr = bindings::open(&filename)?;
let property_names = bindings::get_property_names(osr)?;
let property_iter = property_names.into_iter().filter_map(|name| {
if let Ok(value) = bindings::get_property_value(osr, &name) {
Some((name, value))
} else {
None
}
});
let properties = Properties::new(property_iter);
Ok(OpenSlide {
osr: bindings::OpenSlideWrapper(osr),
properties,
})
}
#[cfg(feature = "openslide4")]
pub fn new_with_cache<T: AsRef<Path>>(path: T, capacity: usize) -> Result<OpenSlide> {
let osr = OpenSlide::new(path)?;
osr.set_cache(Cache::new(capacity)?);
Ok(osr)
}
#[cfg(feature = "openslide4")]
fn set_cache(&self, cache: Cache) {
bindings::set_cache(*self.osr, *cache.0)
}
pub fn detect_vendor(path: &Path) -> Result<String> {
if !path.exists() {
return Err(OpenSlideError::MissingFile(path.display().to_string()));
}
let filename = path.display().to_string();
bindings::detect_vendor(&filename)
}
pub fn properties(&self) -> &Properties {
&self.properties
}
pub fn get_level_count(&self) -> Result<u32> {
let level_count = bindings::get_level_count(*self.osr)?;
let level_count: u32 = level_count.try_into()?;
Ok(level_count)
}
pub fn get_level_dimensions(&self, level: u32) -> Result<Size> {
let level: i32 = level.try_into()?;
let (width, height) = bindings::get_level_dimensions(*self.osr, level)?;
Ok(Size {
w: width.try_into()?,
h: height.try_into()?,
})
}
pub fn get_all_level_dimensions(&self) -> Result<Vec<Size>> {
let nb_levels = self.get_level_count()?;
let mut res = Vec::with_capacity(nb_levels as usize);
for level in 0..nb_levels {
let level: i32 = level.try_into()?;
let (width, height) = bindings::get_level_dimensions(*self.osr, level)?;
res.push(Size {
w: width.try_into()?,
h: height.try_into()?,
});
}
Ok(res)
}
pub fn get_level_downsample(&self, level: u32) -> Result<f64> {
let level: i32 = level.try_into()?;
bindings::get_level_downsample(*self.osr, level)
}
pub fn get_all_level_downsample(&self) -> Result<Vec<f64>> {
let nb_levels = self.get_level_count()?;
let mut res = Vec::with_capacity(nb_levels as usize);
for level in 0..nb_levels {
let downsample = bindings::get_level_downsample(*self.osr, level as i32)?;
res.push(downsample);
}
Ok(res)
}
pub fn get_best_level_for_downsample(&self, downsample: f64) -> Result<u32> {
Ok(bindings::get_best_level_for_downsample(*self.osr, downsample)? as u32)
}
pub fn get_property_names(&self) -> Vec<String> {
bindings::get_property_names(*self.osr).unwrap_or_else(|_| vec![])
}
pub fn get_property_value(&self, name: &str) -> Result<String> {
bindings::get_property_value(*self.osr, name)
}
pub fn read_region(&self, region: &Region) -> Result<Vec<u8>> {
bindings::read_region(
*self.osr,
region.address.x as i64,
region.address.y as i64,
region.level.try_into()?,
region.size.w as i64,
region.size.h as i64,
)
}
pub fn get_associated_image_names(&self) -> Result<Vec<String>> {
bindings::get_associated_image_names(*self.osr)
}
pub fn read_associated_buffer(&self, name: &str) -> Result<(Size, Vec<u8>)> {
let ((width, height), buffer) = bindings::read_associated_image(*self.osr, name)?;
let size = Size {
w: width.try_into()?,
h: height.try_into()?,
};
Ok((size, buffer))
}
pub fn get_associated_image_dimensions(&self, name: &str) -> Result<Size> {
let (width, height) = bindings::get_associated_image_dimensions(*self.osr, name)?;
Ok(Size {
w: width.try_into()?,
h: height.try_into()?,
})
}
#[cfg(feature = "image")]
pub fn read_image_rgba(&self, region: &Region) -> Result<RgbaImage> {
let buffer = self.read_region(region)?;
let size = region.size;
let mut image = RgbaImage::from_vec(size.w, size.h, buffer).unwrap(); _bgra_to_rgba_inplace(&mut image);
Ok(image)
}
#[cfg(feature = "image")]
pub fn read_image_rgb(&self, region: &Region) -> Result<RgbImage> {
let buffer = self.read_region(region)?;
let size = region.size;
let image = RgbaImage::from_vec(size.w, size.h, buffer).unwrap(); Ok(_bgra_to_rgb(&image))
}
#[cfg(feature = "image")]
pub fn read_associated_image_rgba(&self, name: &str) -> Result<RgbaImage> {
let (size, buffer) = self.read_associated_buffer(name)?;
let mut image = RgbaImage::from_vec(size.w, size.h, buffer).unwrap(); _bgra_to_rgba_inplace(&mut image);
Ok(image)
}
#[cfg(feature = "image")]
pub fn read_associated_image_rgb(&self, name: &str) -> Result<RgbImage> {
let (size, buffer) = self.read_associated_buffer(name)?;
let image = RgbaImage::from_vec(size.w, size.h, buffer).unwrap(); Ok(_bgra_to_rgb(&image))
}
#[cfg(feature = "image")]
pub fn thumbnail_rgba(&self, size: &Size) -> Result<RgbaImage> {
let dimension_level0 = self.get_level_dimensions(0)?;
let downsample = (
dimension_level0.w as f64 / size.w as f64,
dimension_level0.h as f64 / size.h as f64,
);
let downsample = f64::max(downsample.0, downsample.1);
let level = self.get_best_level_for_downsample(downsample)?;
let region = Region {
size: self.get_level_dimensions(level)?,
level,
address: Address { x: 0, y: 0 },
};
let image = self.read_image_rgba(®ion)?;
let image = resize_rgba_image(image, size)?;
Ok(image)
}
#[cfg(feature = "image")]
pub fn thumbnail_rgb(&self, size: &Size) -> Result<RgbImage> {
let dimension_level0 = self.get_level_dimensions(0)?;
let downsample = (
dimension_level0.w as f64 / size.w as f64,
dimension_level0.h as f64 / size.h as f64,
);
let downsample = f64::max(downsample.0, downsample.1);
let level = self.get_best_level_for_downsample(downsample)?;
let region = Region {
size: self.get_level_dimensions(level)?,
level,
address: Address { x: 0, y: 0 },
};
let image = self.read_image_rgb(®ion)?;
let image = resize_rgb_image(image, size)?;
Ok(image)
}
#[cfg(feature = "openslide4")]
pub fn icc_profile(&self) -> Result<Vec<u8>> {
bindings::read_icc_profile(*self.osr)
}
#[cfg(feature = "openslide4")]
pub fn associated_image_icc_profile(&self, name: &str) -> Result<Vec<u8>> {
bindings::read_associated_image_icc_profile(*self.osr, name)
}
}
#[cfg(feature = "deepzoom")]
use {crate::deepzoom::Bounds, crate::traits::Slide};
#[cfg(feature = "deepzoom")]
impl Slide for OpenSlide {
fn get_bounds(&self) -> Bounds {
let properties = &self.properties().openslide_properties;
Bounds {
x: properties.bounds_x,
y: properties.bounds_y,
width: properties.bounds_width,
height: properties.bounds_height,
}
}
fn get_level_count(&self) -> Result<u32> {
self.get_level_count()
}
fn get_level_dimensions(&self, level: u32) -> Result<Size> {
self.get_level_dimensions(level)
}
fn get_level_downsample(&self, level: u32) -> Result<f64> {
self.get_level_downsample(level)
}
fn get_best_level_for_downsample(&self, downsample: f64) -> Result<u32> {
self.get_best_level_for_downsample(downsample)
}
fn read_image_rgba(&self, region: &Region) -> Result<RgbaImage> {
self.read_image_rgba(region)
}
fn read_image_rgb(&self, region: &Region) -> Result<RgbImage> {
self.read_image_rgb(region)
}
}