Skip to content

Commit

Permalink
suggestions
Browse files Browse the repository at this point in the history
  • Loading branch information
fabien-brulport committed Sep 11, 2024
1 parent 50d96d2 commit 36dcf7a
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 29 deletions.
31 changes: 27 additions & 4 deletions src/bindings.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! This module contains the bindings to the Philips Open Pathology C++ library
//!

use crate::errors::PhilipsSlideError;

#[cxx::bridge]
pub(crate) mod ffi {
/// Simple struct Size with width and height for an image/tile
Expand Down Expand Up @@ -129,10 +131,31 @@ impl ffi::Size {
pub fn new(w: u32, h: u32) -> Self {
Self { w, h }
}
pub fn from_dimensions_range(range: &ffi::DimensionsRange) -> Self {
Self {
w: (range.end_x - range.start_x) / range.step_x,
h: (range.end_y - range.start_y) / range.step_y,
}
impl TryFrom<&ffi::DimensionsRange> for ffi::Size {
type Error = PhilipsSlideError;

fn try_from(value: &ffi::DimensionsRange) -> Result<Self, Self::Error> {
if value.step_x == 0 || value.step_y == 0 {
return Err(PhilipsSlideError::ConversionError(
"Step is zero!".to_string(),
));

Check warning on line 142 in src/bindings.rs

View check run for this annotation

Codecov / codecov/patch

src/bindings.rs#L140-L142

Added lines #L140 - L142 were not covered by tests
}
if let Some(width) = value.end_x.checked_sub(value.start_x) {
if let Some(height) = value.end_y.checked_sub(value.start_y) {
Ok(Self {
w: width / value.step_x,
h: height / value.step_y,
})
} else {
Err(PhilipsSlideError::ConversionError(
"Height is less than zero!".to_string(),
))

Check warning on line 153 in src/bindings.rs

View check run for this annotation

Codecov / codecov/patch

src/bindings.rs#L151-L153

Added lines #L151 - L153 were not covered by tests
}
} else {
Err(PhilipsSlideError::ConversionError(
"Width is less than zero!".to_string(),
))

Check warning on line 158 in src/bindings.rs

View check run for this annotation

Codecov / codecov/patch

src/bindings.rs#L156-L158

Added lines #L156 - L158 were not covered by tests
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use cxx::Exception;
use std::str::Utf8Error;
use thiserror::Error;

/// Enum defining all possible error when manipulating OpenSlide struct
/// Enum defining all possible error when manipulating Philips struct
#[derive(Error, Debug)]
pub enum PhilipsSlideError {
/// CxxString to &str conversion error
Expand All @@ -21,6 +21,8 @@ pub enum PhilipsSlideError {
#[cfg(feature = "image")]
#[error(transparent)]
ImageError(#[from] ImageError),
#[error("{0}")]
ConversionError(String),
}

#[cfg(feature = "image")]
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pub mod errors;
mod facade;
mod pixel_engine;
mod sub_image;
#[cfg(feature = "image")]
mod utils;
mod view;

Expand Down
26 changes: 6 additions & 20 deletions src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
use crate::{Result, Size};
use std::cmp;

#[cfg(feature = "image")]
use fast_image_resize as fr;
#[cfg(feature = "image")]
use std::cmp;
use {crate::errors::ImageError, image::RgbImage};

// Get the appropriate level for the given dimensions: i.e. the level with at least one
// dimensions (i.e along one axis) greater than the dimension requested
#[cfg(feature = "image")]
pub fn get_best_level_for_dimensions(
dimension: &Size,
dimension_level_0: &Size,
Expand All @@ -18,21 +14,13 @@ pub fn get_best_level_for_dimensions(
f64::from(dimension_level_0.w) / f64::from(dimension.w),
f64::from(dimension_level_0.h) / f64::from(dimension.h),
);
let level_dowsamples: Vec<f64> = (0..level_count)
(0..level_count)
.map(|level| 2_u32.pow(level) as f64)
.collect();
if downsample < 1.0 {
return 0;
}
for i in 1..level_count {
if downsample < level_dowsamples[i as usize] {
return i - 1;
}
}
level_count - 1
.enumerate()
.rfind(|(_, ds)| ds <= &downsample)
.map_or(0, |(index, _)| index) as u32
}

#[cfg(feature = "image")]
pub(crate) fn resize_rgb_image(image: RgbImage, new_size: &Size) -> Result<RgbImage> {
let src_image = fr::images::Image::from_vec_u8(
image.width(),
Expand All @@ -57,7 +45,6 @@ pub(crate) fn resize_rgb_image(image: RgbImage, new_size: &Size) -> Result<RgbIm
Ok(image)
}

#[cfg(feature = "image")]
pub(crate) fn preserve_aspect_ratio(size: &Size, dimension: &Size) -> Size {
// Code adapted from https://pillow.readthedocs.io/en/latest/_modules/PIL/Image.html#Image.thumbnail
fn round_aspect<F: FnMut(f32) -> f32>(number: f32, mut key: F) -> u32 {
Expand Down Expand Up @@ -91,7 +78,6 @@ pub(crate) fn preserve_aspect_ratio(size: &Size, dimension: &Size) -> Size {
}

#[cfg(test)]
#[cfg(feature = "image")]
mod tests {
use super::*;
use rstest::rstest;
Expand All @@ -110,8 +96,8 @@ mod tests {
// 9: Size { w: 307, h: 175 },
// }
#[rstest]
#[case(Size::new(500, 500), 8)]
#[case(Size::new(100, 100), 9)]
#[case(Size::new(500, 500), 8)]
#[case(Size::new(800, 800), 7)]
#[case(Size::new(100000, 100000), 0)]
#[case(Size::new(200000, 200000), 0)]
Expand Down
5 changes: 2 additions & 3 deletions src/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ impl<'a> View<'a> {
#[cfg(feature = "image")]
pub fn read_thumbnail(&self, engine: &PhilipsEngine, size: &Size) -> Result<RgbImage> {
let level_count = self.num_derived_levels() + 1;
let dimension_level_0 = Size::from_dimensions_range(&self.dimension_ranges(0)?);
let dimension_level_0 = Size::try_from(&self.dimension_ranges(0)?)?;
let best_level = get_best_level_for_dimensions(&size, &dimension_level_0, level_count);
let dimensions_range = self.dimension_ranges(best_level)?;
let region_request = RegionRequest {
Expand All @@ -144,8 +144,7 @@ impl<'a> View<'a> {
level: best_level,
};
let image = self.read_image(engine, &region_request)?;
let final_size =
preserve_aspect_ratio(&size, &Size::from_dimensions_range(&dimensions_range));
let final_size = preserve_aspect_ratio(&size, &Size::try_from(&dimensions_range)?);
let image = resize_rgb_image(image, &final_size)?;
Ok(image)
}
Expand Down
12 changes: 11 additions & 1 deletion tests/test_read_thumbnail.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,17 @@ fn test_thumbnail(
let view = image.view().unwrap();

let thumbnail = view.read_thumbnail(&engine, &size).unwrap();
thumbnail.save(format!("thumbnail{0}.jpg", size.w)).unwrap();
thumbnail
.save(format!(
"{0}_thumbnail_{1}.jpg",
filename
.file_stem()
.expect("Invalid file name")
.to_str()
.expect("Invalide file name"),
size.w
))
.unwrap();

// Make sure one of the dimensions is equal to the requested one
// and the other one is smaller than the requested one
Expand Down

0 comments on commit 36dcf7a

Please sign in to comment.