-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
bfa4050
commit c929fff
Showing
8 changed files
with
329 additions
and
7 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
use crate::{Result, Size}; | ||
use fast_image_resize as fr; | ||
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 | ||
pub fn get_best_level_for_dimensions( | ||
dimension: &Size, | ||
dimension_level_0: &Size, | ||
level_count: u32, | ||
) -> u32 { | ||
let downsample = f64::max( | ||
f64::from(dimension_level_0.w) / f64::from(dimension.w), | ||
f64::from(dimension_level_0.h) / f64::from(dimension.h), | ||
); | ||
(0..level_count) | ||
.map(|level| 2_u32.pow(level) as f64) | ||
.enumerate() | ||
.rfind(|(_, ds)| ds <= &downsample) | ||
.map_or(0, |(index, _)| index) as u32 | ||
} | ||
|
||
pub(crate) fn resize_rgb_image(image: RgbImage, new_size: &Size) -> Result<RgbImage> { | ||
let src_image = fr::images::Image::from_vec_u8( | ||
image.width(), | ||
image.height(), | ||
image.into_raw(), | ||
fr::PixelType::U8x3, | ||
) | ||
.map_err(|err| ImageError::Other(err.to_string()))?; | ||
|
||
let mut dst_image = fr::images::Image::new(new_size.w, new_size.h, fr::PixelType::U8x3); | ||
let mut resizer = fr::Resizer::new(); | ||
let option = fr::ResizeOptions { | ||
algorithm: fr::ResizeAlg::Convolution(fr::FilterType::Lanczos3), | ||
cropping: fr::SrcCropping::None, | ||
mul_div_alpha: false, | ||
}; | ||
resizer | ||
.resize(&src_image, &mut dst_image, &option) | ||
.map_err(|err| ImageError::Other(err.to_string()))?; | ||
let image = RgbImage::from_vec(new_size.w, new_size.h, dst_image.into_vec()).unwrap(); // safe because dst_image buffer is big enough | ||
|
||
Ok(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 { | ||
cmp::max( | ||
cmp::min_by_key(number.floor() as u32, number.ceil() as u32, |n| { | ||
key(*n as f32).round() as u32 | ||
}), | ||
1, | ||
) | ||
} | ||
let w = size.w as f32; | ||
let h = size.h as f32; | ||
let aspect: f32 = dimension.w as f32 / dimension.h as f32; | ||
if { w / h } >= aspect { | ||
Size::new( | ||
round_aspect(h * aspect, |n| (aspect - n / h).abs()), | ||
h as u32, | ||
) | ||
} else { | ||
Size::new( | ||
w as u32, | ||
round_aspect(w / aspect, |n| { | ||
if n == 0. { | ||
0. | ||
} else { | ||
(aspect - w / n).abs() | ||
} | ||
}), | ||
) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
use rstest::rstest; | ||
|
||
// Note: the dimensions for each levels are: | ||
// { | ||
// 0: Size { w: 158726, h: 90627}, | ||
// 1: Size { w: 79361, h: 45313 }, | ||
// 2: Size { w: 39678, h: 22655 }, | ||
// 3: Size { w: 19837, h: 11327 }, | ||
// 4: Size { w: 9917, h: 5663 }, | ||
// 5: Size { w: 4957, h: 2831 }, | ||
// 6: Size { w: 2477, h: 1415 }, | ||
// 7: Size { w: 1237, h: 707 }, | ||
// 8: Size { w: 617, h: 353 }, | ||
// 9: Size { w: 307, h: 175 }, | ||
// } | ||
#[rstest] | ||
#[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)] | ||
fn test_get_best_level_for_dimensions(#[case] size: Size, #[case] expected_level: u32) { | ||
let dimension_level_0 = Size::new(158726, 90627); | ||
let level_count = 10; | ||
assert_eq!( | ||
get_best_level_for_dimensions(&size, &dimension_level_0, level_count), | ||
expected_level | ||
); | ||
} | ||
|
||
#[test] | ||
fn test_preserve_aspect_ratio() { | ||
assert_eq!( | ||
preserve_aspect_ratio(&Size { w: 100, h: 100 }, &Size { w: 50, h: 50 }), | ||
Size { w: 100, h: 100 } | ||
); | ||
assert_eq!( | ||
preserve_aspect_ratio(&Size { w: 100, h: 100 }, &Size { w: 25, h: 50 }), | ||
Size { w: 50, h: 100 } | ||
); | ||
assert_eq!( | ||
// Edge case | ||
preserve_aspect_ratio(&Size { w: 1, h: 1 }, &Size { w: 25, h: 50 }), | ||
Size { w: 1, h: 1 } | ||
); | ||
assert_eq!( | ||
// Edge case | ||
preserve_aspect_ratio(&Size { w: 100, h: 200 }, &Size { w: 1, h: 1 }), | ||
Size { w: 100, h: 100 } | ||
); | ||
assert_eq!( | ||
// Edge case | ||
preserve_aspect_ratio(&Size { w: 0, h: 5 }, &Size { w: 1, h: 10 }), | ||
Size { w: 0, h: 1 } | ||
); | ||
assert_eq!( | ||
// Not round ratio | ||
preserve_aspect_ratio(&Size { w: 33, h: 100 }, &Size { w: 12, h: 13 }), | ||
Size { w: 33, h: 35 } | ||
); | ||
assert_eq!( | ||
// Not round ratio | ||
preserve_aspect_ratio(&Size { w: 33, h: 15 }, &Size { w: 12, h: 13 }), | ||
Size { w: 13, h: 15 } | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
c929fff
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
philips-isyntax-rs Benchmark
philips_i2syntax_read_region_256_lvl_0
1403494
ns/iter (± 117595
)1412270
ns/iter (± 62346
)0.99
philips_i2syntax_read_region_256_lvl_1
1195750
ns/iter (± 41157
)1159410
ns/iter (± 68066
)1.03
philips_i2syntax_read_region_512_lvl_0
1600868
ns/iter (± 83291
)1548425
ns/iter (± 62419
)1.03
philips_i2syntax_read_region_512_lvl_1
7555576
ns/iter (± 303817
)7328200
ns/iter (± 306020
)1.03
philips_read_region_256_lvl_0
527964
ns/iter (± 51115
)496517
ns/iter (± 36965
)1.06
philips_read_region_256_lvl_1
1275675
ns/iter (± 78150
)1231938
ns/iter (± 77419
)1.04
philips_read_region_512_lvl_0
3643864
ns/iter (± 185213
)3516623
ns/iter (± 186623
)1.04
philips_read_region_512_lvl_1
3216732
ns/iter (± 209597
)2741562
ns/iter (± 149690
)1.17
This comment was automatically generated by workflow using github-action-benchmark.
c929fff
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
philips-isyntax-rs Benchmark
philips_i2syntax_read_region_256_lvl_0
1361649
ns/iter (± 55947
)1412270
ns/iter (± 62346
)0.96
philips_i2syntax_read_region_256_lvl_1
1165858
ns/iter (± 64534
)1159410
ns/iter (± 68066
)1.01
philips_i2syntax_read_region_512_lvl_0
1579088
ns/iter (± 50537
)1548425
ns/iter (± 62419
)1.02
philips_i2syntax_read_region_512_lvl_1
7437832
ns/iter (± 382315
)7328200
ns/iter (± 306020
)1.01
philips_read_region_256_lvl_0
516789
ns/iter (± 54611
)496517
ns/iter (± 36965
)1.04
philips_read_region_256_lvl_1
1270381
ns/iter (± 98449
)1231938
ns/iter (± 77419
)1.03
philips_read_region_512_lvl_0
3610729
ns/iter (± 192869
)3516623
ns/iter (± 186623
)1.03
philips_read_region_512_lvl_1
3196911
ns/iter (± 167831
)2741562
ns/iter (± 149690
)1.17
This comment was automatically generated by workflow using github-action-benchmark.