1use crate::{OpenSlide, Properties, Region, Result, Size, bindings, errors::OpenSlideError};
2use std::path::Path;
3
4#[cfg(feature = "image")]
5use {
6 crate::{
7 Address,
8 utils::{
9 _bgra_to_rgb, _bgra_to_rgba_inplace, preserve_aspect_ratio, resize_rgb_image,
10 resize_rgba_image,
11 },
12 },
13 image::{RgbImage, RgbaImage},
14};
15
16#[cfg(feature = "openslide4")]
17use crate::cache::Cache;
18
19impl Drop for OpenSlide {
20 fn drop(&mut self) {
21 bindings::close(*self.osr);
22 }
23}
24
25impl OpenSlide {
26 pub fn get_version() -> Result<String> {
28 bindings::get_version()
29 }
30
31 pub fn new<T: AsRef<Path>>(path: T) -> Result<OpenSlide> {
37 let path = path.as_ref();
38 if !path.exists() {
39 return Err(OpenSlideError::MissingFile(path.display().to_string()));
40 }
41
42 let filename = path.display().to_string();
43 let osr = bindings::open(&filename)?;
44
45 let property_names = bindings::get_property_names(osr)?;
46
47 let property_iter = property_names.into_iter().filter_map(|name| {
48 bindings::get_property_value(osr, &name)
49 .map(|value| (name, value))
50 .ok()
51 });
52
53 let properties = Properties::new(property_iter);
54
55 Ok(OpenSlide {
56 osr: bindings::OpenSlideWrapper(osr),
57 properties,
58 })
59 }
60
61 #[cfg(feature = "openslide4")]
62 pub fn new_with_cache<T: AsRef<Path>>(path: T, capacity: usize) -> Result<OpenSlide> {
63 let osr = OpenSlide::new(path)?;
64 osr.set_cache(Cache::new(capacity)?);
65 Ok(osr)
66 }
67
68 #[cfg(feature = "openslide4")]
69 fn set_cache(&self, cache: Cache) {
70 bindings::set_cache(*self.osr, *cache.0);
71 }
72
73 pub fn detect_vendor(path: &Path) -> Result<String> {
75 if !path.exists() {
76 return Err(OpenSlideError::MissingFile(path.display().to_string()));
77 }
78 let filename = path.display().to_string();
79 bindings::detect_vendor(&filename)
80 }
81
82 #[must_use]
83 pub fn properties(&self) -> &Properties {
84 &self.properties
85 }
86
87 pub fn get_level_count(&self) -> Result<u32> {
89 let level_count = bindings::get_level_count(*self.osr)?;
90 let level_count: u32 = level_count.try_into()?;
91 Ok(level_count)
92 }
93
94 pub fn get_level_dimensions(&self, level: u32) -> Result<Size> {
99 let level: i32 = level.try_into()?;
100 let (width, height) = bindings::get_level_dimensions(*self.osr, level)?;
101 Ok(Size {
102 w: width.try_into()?,
103 h: height.try_into()?,
104 })
105 }
106
107 pub fn get_all_level_dimensions(&self) -> Result<Vec<Size>> {
109 let nb_levels = self.get_level_count()?;
110 let mut res = Vec::with_capacity(nb_levels as usize);
111 for level in 0..nb_levels {
112 let level: i32 = level.try_into()?;
113 let (width, height) = bindings::get_level_dimensions(*self.osr, level)?;
114 res.push(Size {
115 w: width.try_into()?,
116 h: height.try_into()?,
117 });
118 }
119 Ok(res)
120 }
121
122 pub fn get_level_downsample(&self, level: u32) -> Result<f64> {
124 let level: i32 = level.try_into()?;
125 bindings::get_level_downsample(*self.osr, level)
126 }
127
128 pub fn get_all_level_downsample(&self) -> Result<Vec<f64>> {
130 let nb_levels = self.get_level_count()?;
131 let mut res = Vec::with_capacity(nb_levels as usize);
132 for level in 0..nb_levels {
133 let downsample = bindings::get_level_downsample(*self.osr, level as i32)?;
134 res.push(downsample);
135 }
136 Ok(res)
137 }
138
139 pub fn get_best_level_for_downsample(&self, downsample: f64) -> Result<u32> {
141 Ok(bindings::get_best_level_for_downsample(*self.osr, downsample)? as u32)
142 }
143
144 #[must_use]
146 pub fn get_property_names(&self) -> Vec<String> {
147 bindings::get_property_names(*self.osr).unwrap_or_else(|_| vec![])
148 }
149
150 pub fn get_property_value(&self, name: &str) -> Result<String> {
152 bindings::get_property_value(*self.osr, name)
153 }
154
155 pub fn read_region(&self, region: &Region) -> Result<Vec<u8>> {
166 bindings::read_region(
167 *self.osr,
168 i64::from(region.address.x),
169 i64::from(region.address.y),
170 region.level.try_into()?,
171 i64::from(region.size.w),
172 i64::from(region.size.h),
173 )
174 }
175
176 pub fn get_associated_image_names(&self) -> Result<Vec<String>> {
178 bindings::get_associated_image_names(*self.osr)
179 }
180
181 pub fn read_associated_buffer(&self, name: &str) -> Result<(Size, Vec<u8>)> {
190 let ((width, height), buffer) = bindings::read_associated_image(*self.osr, name)?;
191 let size = Size {
192 w: width.try_into()?,
193 h: height.try_into()?,
194 };
195 Ok((size, buffer))
196 }
197
198 pub fn get_associated_image_dimensions(&self, name: &str) -> Result<Size> {
200 let (width, height) = bindings::get_associated_image_dimensions(*self.osr, name)?;
201 Ok(Size {
202 w: width.try_into()?,
203 h: height.try_into()?,
204 })
205 }
206
207 #[cfg(feature = "image")]
216 pub fn read_image_rgba(&self, region: &Region) -> Result<RgbaImage> {
217 let buffer = self.read_region(region)?;
218 let size = region.size;
219 let mut image = RgbaImage::from_vec(size.w, size.h, buffer).unwrap(); _bgra_to_rgba_inplace(&mut image);
221 Ok(image)
222 }
223
224 #[cfg(feature = "image")]
233 pub fn read_image_rgb(&self, region: &Region) -> Result<RgbImage> {
234 let buffer = self.read_region(region)?;
235 let size = region.size;
236 let image = RgbaImage::from_vec(size.w, size.h, buffer).unwrap(); Ok(_bgra_to_rgb(&image))
238 }
239
240 #[cfg(feature = "image")]
247 pub fn read_associated_image_rgba(&self, name: &str) -> Result<RgbaImage> {
248 let (size, buffer) = self.read_associated_buffer(name)?;
249 let mut image = RgbaImage::from_vec(size.w, size.h, buffer).unwrap(); _bgra_to_rgba_inplace(&mut image);
251 Ok(image)
252 }
253
254 #[cfg(feature = "image")]
261 pub fn read_associated_image_rgb(&self, name: &str) -> Result<RgbImage> {
262 let (size, buffer) = self.read_associated_buffer(name)?;
263 let image = RgbaImage::from_vec(size.w, size.h, buffer).unwrap(); Ok(_bgra_to_rgb(&image))
265 }
266
267 #[cfg(feature = "image")]
271 pub fn thumbnail_rgba(&self, size: &Size) -> Result<RgbaImage> {
272 let dimension_level0 = self.get_level_dimensions(0)?;
273
274 let downsample = (
275 f64::from(dimension_level0.w) / f64::from(size.w),
276 f64::from(dimension_level0.h) / f64::from(size.h),
277 );
278 let downsample = f64::max(downsample.0, downsample.1);
279
280 let level = self.get_best_level_for_downsample(downsample)?;
281
282 let region = Region {
283 size: self.get_level_dimensions(level)?,
284 level,
285 address: Address { x: 0, y: 0 },
286 };
287 let image = self.read_image_rgba(®ion)?;
288 let size = preserve_aspect_ratio(size, &dimension_level0);
289 let image = resize_rgba_image(image, &size)?;
290
291 Ok(image)
292 }
293
294 #[cfg(feature = "image")]
298 pub fn thumbnail_rgb(&self, size: &Size) -> Result<RgbImage> {
299 let dimension_level0 = self.get_level_dimensions(0)?;
300
301 let downsample = (
302 f64::from(dimension_level0.w) / f64::from(size.w),
303 f64::from(dimension_level0.h) / f64::from(size.h),
304 );
305 let downsample = f64::max(downsample.0, downsample.1);
306
307 let level = self.get_best_level_for_downsample(downsample)?;
308
309 let region = Region {
310 size: self.get_level_dimensions(level)?,
311 level,
312 address: Address { x: 0, y: 0 },
313 };
314
315 let image = self.read_image_rgb(®ion)?;
316 let size = preserve_aspect_ratio(size, &dimension_level0);
317 let image = resize_rgb_image(image, &size)?;
318
319 Ok(image)
320 }
321
322 #[cfg(feature = "openslide4")]
323 pub fn icc_profile(&self) -> Result<Vec<u8>> {
324 bindings::read_icc_profile(*self.osr)
325 }
326
327 #[cfg(feature = "openslide4")]
328 pub fn associated_image_icc_profile(&self, name: &str) -> Result<Vec<u8>> {
329 bindings::read_associated_image_icc_profile(*self.osr, name)
330 }
331}
332
333#[cfg(feature = "deepzoom")]
334use {crate::deepzoom::Bounds, crate::traits::Slide};
335
336#[cfg(feature = "deepzoom")]
337impl Slide for OpenSlide {
338 fn get_bounds(&self) -> Bounds {
339 let properties = &self.properties().openslide_properties;
340 Bounds {
341 x: properties.bounds_x,
342 y: properties.bounds_y,
343 width: properties.bounds_width,
344 height: properties.bounds_height,
345 }
346 }
347
348 fn get_level_count(&self) -> Result<u32> {
349 self.get_level_count()
350 }
351
352 fn get_level_dimensions(&self, level: u32) -> Result<Size> {
353 self.get_level_dimensions(level)
354 }
355
356 fn get_level_downsample(&self, level: u32) -> Result<f64> {
357 self.get_level_downsample(level)
358 }
359
360 fn get_best_level_for_downsample(&self, downsample: f64) -> Result<u32> {
361 self.get_best_level_for_downsample(downsample)
362 }
363
364 fn read_image_rgba(&self, region: &Region) -> Result<RgbaImage> {
365 self.read_image_rgba(region)
366 }
367
368 fn read_image_rgb(&self, region: &Region) -> Result<RgbImage> {
369 self.read_image_rgb(region)
370 }
371}