- Added Gaussian filter for convolution algorithm.

- Added field `algorithm` into `ResizeOptions`.
- Argument `resize_alg` was removed from `Resizer::new()` method, use `options` argument of methods to resize instead.
This commit is contained in:
Kirill Kuzminykh
2024-05-02 21:41:41 +03:00
parent 8af42a2cf7
commit 2bc54792f2
13 changed files with 234 additions and 197 deletions
+5 -2
View File
@@ -2,7 +2,7 @@
### Added
- Added Gaussian filter for convolution algorythm.
- Added Gaussian filter for convolution algorithm.
### Fixed
@@ -25,11 +25,14 @@ A lot of breaking changes have been done in this release:
- `resize_typed()` accepts references to `impl ImageView` and `impl ImageViewMut`.
- Resize methods also accept the `options` argument.
With the help of this argument, you can specify:
- resize algorithm;
- how to crop the source image;
- whether to multiply the source image by the alpha channel and
divide the destination image by the alpha channel.
By default, Resizer multiplies and divides by alpha channel
images with `U8x2`, `U8x4`, `U16x2` and `U16x4` pixels.
- Argument `resize_alg` was removed from `Resizer::new()` method, use
`options` argument of methods to resize instead.
- The `MulDiv` implementation has been changed in the same way as `Resizer`.
It now has two versions of each method: dynamic and typed.
- Type of image dimensions has been changed from `NonZeroU32` into `u32`.
@@ -135,7 +138,7 @@ fn my_resize(
// Create Resizer instance and resize source image
// into buffer of destination image.
let mut resizer = Resizer::default();
let mut resizer = Resizer::new();
// By default, Resizer multiplies and divides by alpha channel
// images with U8x2, U8x4, U16x2 and U16x4 pixels.
resizer.resize(&src_image, &mut dst_image, None).unwrap();
Generated
+80 -88
View File
@@ -94,9 +94,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.81"
version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247"
checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519"
[[package]]
name = "arbitrary"
@@ -112,7 +112,7 @@ checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.58",
"syn 2.0.60",
]
[[package]]
@@ -217,6 +217,12 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "byteorder-lite"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
[[package]]
name = "cast"
version = "0.3.0"
@@ -225,19 +231,20 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]]
name = "cc"
version = "1.0.92"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41"
checksum = "d32a725bc159af97c3e629873bb9f88fb8cf8a4867175f76dc987815ea07c83b"
dependencies = [
"jobserver",
"libc",
"once_cell",
]
[[package]]
name = "cfg-expr"
version = "0.15.7"
version = "0.15.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa50868b64a9a6fda9d593ce778849ea8715cd2a3d2cc17ffdb4a2f2f2f1961d"
checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02"
dependencies = [
"smallvec",
"target-lexicon",
@@ -257,9 +264,9 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
[[package]]
name = "chrono"
version = "0.4.37"
version = "0.4.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e"
checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
dependencies = [
"android-tzdata",
"iana-time-zone",
@@ -357,7 +364,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.58",
"syn 2.0.60",
]
[[package]]
@@ -479,9 +486,9 @@ dependencies = [
[[package]]
name = "deunicode"
version = "1.4.3"
version = "1.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6e854126756c496b8c81dec88f9a706b15b875c5849d4097a3854476b9fdf94"
checksum = "322ef0094744e63628e6f0eb2295517f79276a5b342a4c2ff3042566ca181d4e"
[[package]]
name = "digest"
@@ -504,9 +511,9 @@ dependencies = [
[[package]]
name = "either"
version = "1.10.0"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2"
[[package]]
name = "env_filter"
@@ -768,11 +775,11 @@ dependencies = [
[[package]]
name = "image-webp"
version = "0.1.1"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a84a25dcae3ac487bc24ef280f9e20c79c9b1a3e5e32cbed3041d1c514aa87c"
checksum = "d730b085583c4d789dfd07fdcf185be59501666a90c97c40162b37e4fdad272d"
dependencies = [
"byteorder",
"byteorder-lite",
"thiserror",
]
@@ -800,7 +807,7 @@ checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.58",
"syn 2.0.60",
]
[[package]]
@@ -840,9 +847,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "jobserver"
version = "0.1.28"
version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6"
checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e"
dependencies = [
"libc",
]
@@ -1034,7 +1041,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.58",
"syn 2.0.60",
]
[[package]]
@@ -1131,7 +1138,7 @@ dependencies = [
"pest_meta",
"proc-macro2",
"quote",
"syn 2.0.58",
"syn 2.0.60",
]
[[package]]
@@ -1210,9 +1217,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro2"
version = "1.0.79"
version = "1.0.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba"
dependencies = [
"unicode-ident",
]
@@ -1233,7 +1240,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8021cf59c8ec9c432cfc2526ac6b8aa508ecaf29cd415f271b8406c1b851c3fd"
dependencies = [
"quote",
"syn 2.0.58",
"syn 2.0.60",
]
[[package]]
@@ -1253,9 +1260,9 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
[[package]]
name = "quote"
version = "1.0.35"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
@@ -1445,29 +1452,29 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "serde"
version = "1.0.197"
version = "1.0.198"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.197"
version = "1.0.198"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.58",
"syn 2.0.60",
]
[[package]]
name = "serde_json"
version = "1.0.115"
version = "1.0.116"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd"
checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813"
dependencies = [
"itoa",
"ryu",
@@ -1559,9 +1566,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.58"
version = "2.0.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687"
checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3"
dependencies = [
"proc-macro2",
"quote",
@@ -1619,22 +1626,22 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.58"
version = "1.0.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297"
checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.58"
version = "1.0.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.58",
"syn 2.0.60",
]
[[package]]
@@ -1681,9 +1688,9 @@ dependencies = [
[[package]]
name = "toml_edit"
version = "0.22.9"
version = "0.22.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4"
checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef"
dependencies = [
"indexmap",
"serde",
@@ -1826,7 +1833,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.58",
"syn 2.0.60",
"wasm-bindgen-shared",
]
@@ -1848,7 +1855,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.58",
"syn 2.0.60",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@@ -1865,37 +1872,15 @@ version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.6"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
checksum = "134306a13c5647ad6453e8deaec55d3a44d6021970129e6188735e74bf546697"
dependencies = [
"winapi",
"windows-sys",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-core"
version = "0.52.0"
@@ -1916,13 +1901,14 @@ dependencies = [
[[package]]
name = "windows-targets"
version = "0.52.4"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
@@ -1931,51 +1917,57 @@ dependencies = [
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.4"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.4"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
[[package]]
name = "windows_i686_gnu"
version = "0.52.4"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
[[package]]
name = "windows_i686_msvc"
version = "0.52.4"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.4"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.4"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.4"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
[[package]]
name = "winnow"
version = "0.6.5"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8"
checksum = "f0c976aaaa0e1f90dbb21e9587cdaf1d9679a1cde8875c0d6bd83ab96a208352"
dependencies = [
"memchr",
]
+11 -13
View File
@@ -126,7 +126,7 @@ Pipeline:
### Resize RGBA8 image
Note:: You must enable `"image"` feature to support of
Note: You must enable `"image"` feature to support of
[image::DynamicImage](https://docs.rs/image/latest/image/enum.DynamicImage.html).
Otherwise, you have to convert such images into supported by the crate image type.
@@ -137,7 +137,8 @@ use image::codecs::png::PngEncoder;
use image::io::Reader as ImageReader;
use image::{ExtendedColorType, ImageEncoder};
use fast_image_resize::{self as fr, IntoImageView};
use fast_image_resize::{IntoImageView, Resizer};
use fast_image_resize::images::Image;
fn main() {
// Read source image from file
@@ -149,7 +150,7 @@ fn main() {
// Create container for data of destination image
let dst_width = 1024;
let dst_height = 768;
let mut dst_image = fr::images::Image::new(
let mut dst_image = Image::new(
dst_width,
dst_height,
src_image.pixel_type().unwrap(),
@@ -157,9 +158,7 @@ fn main() {
// Create Resizer instance and resize source image
// into buffer of destination image
let mut resizer = fr::Resizer::new(
fr::ResizeAlg::Convolution(fr::FilterType::Lanczos3),
);
let mut resizer = Resizer::new();
resizer.resize(&src_image, &mut dst_image, None).unwrap();
// Write destination image as PNG-file
@@ -182,7 +181,8 @@ use image::codecs::png::PngEncoder;
use image::io::Reader as ImageReader;
use image::{ColorType, GenericImageView};
use fast_image_resize::{self as fr, IntoImageView};
use fast_image_resize::{IntoImageView, Resizer, ResizeOptions};
use fast_image_resize::images::Image;
fn main() {
let img = ImageReader::open("./data/nasa-4928x3279.png")
@@ -191,21 +191,19 @@ fn main() {
.unwrap();
// Create container for data of destination image
let mut dst_image = fr::images::Image::new(
let mut dst_image = Image::new(
1024,
768,
img.pixel_type().unwrap(),
);
// Create Resizer instance and resize source image
// Create Resizer instance and resize cropped source image
// into buffer of destination image
let mut resizer = fr::Resizer::new(
fr::ResizeAlg::Convolution(fr::FilterType::Lanczos3),
);
let mut resizer = Resizer::new();
resizer.resize(
&img,
&mut dst_image,
&fr::ResizeOptions::new().crop(
&ResizeOptions::new().crop(
10.0, // left
10.0, // top
2000.0, // width
+18 -6
View File
@@ -11,12 +11,17 @@ const NEW_SIZE: u32 = 695;
fn native_nearest_u8x4_bench(bench_group: &mut utils::BenchGroup) {
let src_image = U8x4::load_big_square_src_image();
let mut dst_image = Image::new(NEW_SIZE, NEW_SIZE, PixelType::U8x4);
let mut resizer = Resizer::new(ResizeAlg::Nearest);
let mut resizer = Resizer::new();
let options = ResizeOptions::new().resize_alg(ResizeAlg::Nearest);
unsafe {
resizer.set_cpu_extensions(CpuExtensions::None);
}
utils::bench(bench_group, 100, "U8x4 Nearest", "rust", |bencher| {
bencher.iter(|| resizer.resize(&src_image, &mut dst_image, None).unwrap())
bencher.iter(|| {
resizer
.resize(&src_image, &mut dst_image, &options)
.unwrap()
})
});
}
@@ -24,12 +29,17 @@ fn native_nearest_u8x4_bench(bench_group: &mut utils::BenchGroup) {
fn native_nearest_u8_bench(bench_group: &mut utils::BenchGroup) {
let src_image = U8::load_big_square_src_image();
let mut dst_image = Image::new(NEW_SIZE, NEW_SIZE, PixelType::U8);
let mut resizer = Resizer::new(ResizeAlg::Nearest);
let mut resizer = Resizer::new();
let options = ResizeOptions::new().resize_alg(ResizeAlg::Nearest);
unsafe {
resizer.set_cpu_extensions(CpuExtensions::None);
}
utils::bench(bench_group, 100, "U8 Nearest", "rust", |bencher| {
bencher.iter(|| resizer.resize(&src_image, &mut dst_image, None).unwrap())
bencher.iter(|| {
resizer
.resize(&src_image, &mut dst_image, &options)
.unwrap()
})
});
}
@@ -43,8 +53,10 @@ fn downscale_bench(
name_prefix: &str,
) {
let mut res_image = Image::new(dst_width, dst_height, image.pixel_type());
let mut resizer = Resizer::new(ResizeAlg::Convolution(filter_type));
let options = ResizeOptions::new().use_alpha(false);
let mut resizer = Resizer::new();
let options = ResizeOptions::new()
.resize_alg(ResizeAlg::Convolution(filter_type))
.use_alpha(false);
unsafe {
resizer.set_cpu_extensions(cpu_extensions);
}
+3 -3
View File
@@ -6,14 +6,14 @@ Environment:
- CPU: Neoverse-N1 2GHz (Oracle Cloud Compute, VM.Standard.A1.Flex)
{% else -%}
- CPU: AMD Ryzen 9 5950X
- RAM: DDR4 3800 MHz
- RAM: DDR4 4000 MHz
{% endif -%}
- Ubuntu 22.04 (linux 6.5.0)
- Rust 1.77.2
- Rust 1.78
- criterion = "0.5.1"
- fast_image_resize = "4.0.0"
{% if arch_id == "wasm32" -%}
- wasmtime = "19.0.2"
- wasmtime = "20.0.0"
{% endif %}
Other libraries used to compare of resizing speed:
+4 -2
View File
@@ -180,7 +180,6 @@ mod vips {
/// Resize image with help of "fast_imager_resize" crate
pub fn fir_resize<P: PixelTestingExt>(bench_group: &mut BenchGroup, use_alpha: bool) {
let resize_options = ResizeOptions::new().use_alpha(use_alpha);
let src_image_data = P::load_big_src_image();
let mut dst_image = Image::new(NEW_WIDTH, NEW_HEIGHT, src_image_data.pixel_type());
let mut cpu_extensions = vec![CpuExtensions::None];
@@ -207,11 +206,14 @@ pub fn fir_resize<P: PixelTestingExt>(bench_group: &mut BenchGroup, use_alpha: b
"Lanczos3" => ResizeAlg::Convolution(FilterType::Lanczos3),
_ => continue,
};
let mut fast_resizer = Resizer::new(resize_alg);
let mut fast_resizer = Resizer::new();
unsafe {
fast_resizer.set_cpu_extensions(cpu_ext);
}
let sample_size = 100;
let resize_options = ResizeOptions::new()
.resize_alg(resize_alg)
.use_alpha(use_alpha);
bench(
bench_group,
+7 -2
View File
@@ -10,6 +10,7 @@ use once_cell::sync::Lazy;
use fast_image_resize as fr;
use fast_image_resize::images::Image;
use fast_image_resize::ResizeOptions;
mod structs;
@@ -77,7 +78,7 @@ fn resize(cli: &Cli) -> Result<()> {
let mut dst_image = create_destination_image(cli, &src_image);
let algorithm = get_resizing_algorithm(cli);
let mut resizer = fr::Resizer::new(algorithm);
let mut resizer = fr::Resizer::new();
debug!(
"Resize the source image into {}x{}",
@@ -85,7 +86,11 @@ fn resize(cli: &Cli) -> Result<()> {
dst_image.height()
);
resizer
.resize(&src_image, &mut dst_image, None)
.resize(
&src_image,
&mut dst_image,
&ResizeOptions::new().resize_alg(algorithm),
)
.with_context(|| "Failed to resize image")?;
save_result(cli, dst_image, color_type, orig_pixel_type)
+29 -17
View File
@@ -71,11 +71,15 @@ impl<'a, P: InnerPixel> ImageView for TypedImage<'a, P> {
fn iter_rows(&self, start_row: u32) -> impl Iterator<Item = &[Self::Pixel]> {
let width = self.width as usize;
let start = start_row as usize * width;
self.pixels
.get(start..)
.unwrap_or_default()
.chunks_exact(width)
if width == 0 {
[].chunks_exact(1)
} else {
let start = start_row as usize * width;
self.pixels
.get(start..)
.unwrap_or_default()
.chunks_exact(width)
}
}
fn iter_rows_with_step(
@@ -184,24 +188,32 @@ impl<'a, P: InnerPixel> ImageView for TypedImageMut<'a, P> {
fn iter_rows(&self, start_row: u32) -> impl Iterator<Item = &[Self::Pixel]> {
let width = self.width as usize;
let start = start_row as usize * width;
self.pixels
.borrow()
.get(start..)
.unwrap_or_default()
.chunks_exact(width)
if width == 0 {
[].chunks_exact(1)
} else {
let start = start_row as usize * width;
self.pixels
.borrow()
.get(start..)
.unwrap_or_default()
.chunks_exact(width)
}
}
}
impl<'a, P: InnerPixel> ImageViewMut for TypedImageMut<'a, P> {
fn iter_rows_mut(&mut self, start_row: u32) -> impl Iterator<Item = &mut [Self::Pixel]> {
let width = self.width as usize;
let start = start_row as usize * width;
self.pixels
.borrow_mut()
.get_mut(start..)
.unwrap_or_default()
.chunks_exact_mut(width)
if width == 0 {
[].chunks_exact_mut(1)
} else {
let start = start_row as usize * width;
self.pixels
.borrow_mut()
.get_mut(start..)
.unwrap_or_default()
.chunks_exact_mut(width)
}
}
}
+1
View File
@@ -97,6 +97,7 @@ impl MulDiv {
if src_view.width() != dst_view.width() || src_view.height() != dst_view.height() {
return Err(MulDivImagesError::SizeIsDifferent);
}
P::multiply_alpha(src_view, dst_view, self.cpu_extensions)?;
Ok(())
}
+34 -23
View File
@@ -30,11 +30,15 @@ pub enum SrcCropping {
FitIntoDestination((f64, f64)),
}
/// Options for configuring resize process.
/// Options for configuring a resize process.
#[derive(Debug, Clone, Copy)]
pub struct ResizeOptions {
/// Default: [SrcCropping::None].
/// Default: `ResizeAlg::Convolution(FilterType::Lanczos3)`
pub algorithm: ResizeAlg,
/// Default: `SrcCropping::None`.
pub cropping: SrcCropping,
/// Enable or disable consideration of the alpha channel when resizing.
///
/// Default: `true`.
pub mul_div_alpha: bool,
}
@@ -42,7 +46,8 @@ pub struct ResizeOptions {
impl Default for ResizeOptions {
fn default() -> Self {
Self {
cropping: Default::default(),
algorithm: ResizeAlg::Convolution(FilterType::Lanczos3),
cropping: SrcCropping::None,
mul_div_alpha: true,
}
}
@@ -53,15 +58,23 @@ impl ResizeOptions {
Default::default()
}
/// Set resize algorythm.
pub fn resize_alg(&self, resize_alg: ResizeAlg) -> Self {
let mut options = *self;
options.algorithm = resize_alg;
options
}
/// Set crop box for source image.
pub fn crop(mut self, left: f64, top: f64, width: f64, height: f64) -> Self {
self.cropping = SrcCropping::Crop(CropBox {
pub fn crop(&self, left: f64, top: f64, width: f64, height: f64) -> Self {
let mut options = *self;
options.cropping = SrcCropping::Crop(CropBox {
left,
top,
width,
height,
});
self
options
}
/// Fit source image into the aspect ratio of destination image without distortions.
@@ -76,41 +89,38 @@ impl ResizeOptions {
/// corner, etc. (i.e. if cropping the width, take all the
/// crop off the left side, and if cropping the height take
/// none from the top, and therefore all off the bottom).
pub fn fit_into_destination(mut self, centering: Option<(f64, f64)>) -> Self {
self.cropping = SrcCropping::FitIntoDestination(centering.unwrap_or((0.5, 0.5)));
self
pub fn fit_into_destination(&self, centering: Option<(f64, f64)>) -> Self {
let mut options = *self;
options.cropping = SrcCropping::FitIntoDestination(centering.unwrap_or((0.5, 0.5)));
options
}
/// Enable or disable consideration of the alpha channel when resizing.
pub fn use_alpha(mut self, v: bool) -> Self {
self.mul_div_alpha = v;
self
pub fn use_alpha(&self, v: bool) -> Self {
let mut options = *self;
options.mul_div_alpha = v;
options
}
}
/// Methods of this structure used to resize images.
#[derive(Default, Debug, Clone)]
pub struct Resizer {
pub algorithm: ResizeAlg,
cpu_extensions: CpuExtensions,
mul_div: MulDiv,
default_options: ResizeOptions,
alpha_buffer: Vec<u8>,
convolution_buffer: Vec<u8>,
super_sampling_buffer: Vec<u8>,
}
impl Resizer {
/// Creates instance of `Resizer`
/// Creates instance of `Resizer`.
///
/// By default, instance of `Resizer` created with the best CPU
/// By default, an instance of `Resizer` is created with the best CPU
/// extensions provided by your CPU.
/// You can change this by using method [Resizer::set_cpu_extensions].
pub fn new(algorithm: ResizeAlg) -> Self {
Self {
algorithm,
..Default::default()
}
pub fn new() -> Self {
Default::default()
}
/// Resize the source image to the size of destination image and save
@@ -183,7 +193,8 @@ impl Resizer {
dst_view: &mut impl ImageViewMut<Pixel = P>,
options: impl Into<Option<&'o ResizeOptions>>,
) -> Result<(), ResizeError> {
let options = options.into().unwrap_or(&self.default_options);
let default_options = ResizeOptions::default();
let options = options.into().unwrap_or(&default_options);
let crop_box = match options.cropping {
SrcCropping::None => CropBox {
@@ -210,7 +221,7 @@ impl Resizer {
return Ok(());
}
match self.algorithm {
match options.algorithm {
ResizeAlg::Nearest => resample_nearest(&cropped_src_view, dst_view),
ResizeAlg::Convolution(filter_type) => self.resample_convolution(
&cropped_src_view,
-1
View File
@@ -8,7 +8,6 @@ enum Oper {
Div,
}
#[derive(Clone, Copy)]
struct TestCaseU16 {
pub color: u16,
pub alpha: u16,
+7 -3
View File
@@ -1,7 +1,7 @@
use fast_image_resize as fr;
use fast_image_resize::images::{CroppedImageMut, Image, ImageRef, TypedImage, TypedImageMut};
use fast_image_resize::pixels::{U8x4, U8};
use fast_image_resize::ImageView;
use fast_image_resize::{ImageView, ResizeOptions};
#[test]
fn create_image_ref_from_small_buffer() {
@@ -79,9 +79,13 @@ fn crop_view_mut() {
assert_eq!(cropped_dst_image.width(), 44);
assert_eq!(cropped_dst_image.height(), 12);
let mut resizer = fr::Resizer::new(fr::ResizeAlg::Nearest);
let mut resizer = fr::Resizer::new();
resizer
.resize_typed(&src_image, &mut cropped_dst_image, None)
.resize_typed(
&src_image,
&mut cropped_dst_image,
&ResizeOptions::new().resize_alg(fr::ResizeAlg::Nearest),
)
.unwrap();
let row_size: usize = 64 * 4;
+35 -37
View File
@@ -6,8 +6,8 @@ use image::io::Reader as ImageReader;
use fast_image_resize::images::{Image, TypedImage, TypedImageMut};
use fast_image_resize::pixels::*;
use fast_image_resize::{
testing as fr_testing, CpuExtensions, CropBox, CropBoxError, Filter, FilterType, IntoImageView,
PixelTrait, PixelType, ResizeAlg, ResizeError, ResizeOptions, Resizer, SrcCropping,
testing as fr_testing, CpuExtensions, CropBoxError, Filter, FilterType, IntoImageView,
PixelTrait, PixelType, ResizeAlg, ResizeError, ResizeOptions, Resizer,
};
use testing::{cpu_ext_into_str, image_checksum, save_result, PixelTestingExt};
@@ -21,11 +21,15 @@ const NEW_BIG_WIDTH: u32 = 5016;
#[test]
fn try_resize_to_other_pixel_type() {
let mut resizer = Resizer::new(ResizeAlg::Nearest);
let mut resizer = Resizer::new();
let src_image = U8x4::load_big_src_image();
let mut dst_image = Image::new(1024, 256, PixelType::U8);
assert!(matches!(
resizer.resize(&src_image, &mut dst_image, None),
resizer.resize(
&src_image,
&mut dst_image,
&ResizeOptions::new().resize_alg(ResizeAlg::Nearest),
),
Err(ResizeError::PixelTypesAreDifferent)
));
}
@@ -42,7 +46,7 @@ fn resize_to_same_size() {
let mut dst_image = Image::new(width, height, PixelType::U8x4);
let src_view: TypedImage<U8x4> = src_image.typed_image().unwrap();
let mut dst_view: TypedImageMut<U8x4> = dst_image.typed_image_mut().unwrap();
let mut resizer = Resizer::new(ResizeAlg::Convolution(FilterType::Lanczos3));
let mut resizer = Resizer::new();
resizer
.resize_typed(&src_view, &mut dst_view, None)
.unwrap();
@@ -67,16 +71,8 @@ fn resize_to_same_size_after_cropping() {
let mut dst_image = Image::new(width, height, PixelType::U8x4);
let mut dst_view: TypedImageMut<U8x4> = dst_image.typed_image_mut().unwrap();
let mut resizer = Resizer::new(ResizeAlg::Convolution(FilterType::Lanczos3));
let options = ResizeOptions {
cropping: SrcCropping::Crop(CropBox {
top: 10.,
left: 10.,
width: width as _,
height: height as _,
}),
..Default::default()
};
let mut resizer = Resizer::new();
let options = ResizeOptions::new().crop(10., 10., width as _, height as _);
resizer
.resize_typed(&src_view, &mut dst_view, &options)
.unwrap();
@@ -116,7 +112,7 @@ fn resize_to_same_width<const C: usize>(
let src_image = Image::from_vec_u8(src_width, src_height, buffer, pixel_type).unwrap();
let mut dst_image = Image::new(width, height, pixel_type);
let mut resizer = Resizer::new(ResizeAlg::Convolution(FilterType::Lanczos3));
let mut resizer = Resizer::new();
unsafe {
resizer.set_cpu_extensions(cpu_extensions);
}
@@ -169,7 +165,7 @@ fn resize_to_same_height<const C: usize>(
let src_image = Image::from_vec_u8(src_width, src_height, buffer, pixel_type).unwrap();
let mut dst_image = Image::new(width, height, pixel_type);
let mut resizer = Resizer::new(ResizeAlg::Convolution(FilterType::Lanczos3));
let mut resizer = Resizer::new();
unsafe {
resizer.set_cpu_extensions(cpu_extensions);
}
@@ -289,14 +285,18 @@ where
let image = Self::load_big_src_image();
assert_eq!(image.pixel_type(), Self::pixel_type());
let mut resizer = Resizer::new(resize_alg);
let mut resizer = Resizer::new();
unsafe {
resizer.set_cpu_extensions(cpu_extensions);
}
let new_height = get_new_height(&image, NEW_WIDTH);
let mut result = Image::new(NEW_WIDTH, new_height, image.pixel_type());
resizer
.resize(&image, &mut result, &ResizeOptions::new().use_alpha(false))
.resize(
&image,
&mut result,
&ResizeOptions::new().resize_alg(resize_alg).use_alpha(false),
)
.unwrap();
let alg_name = match resize_alg {
@@ -341,14 +341,18 @@ where
let image = Self::load_small_src_image();
assert_eq!(image.pixel_type(), Self::pixel_type());
let mut resizer = Resizer::new(resize_alg);
let mut resizer = Resizer::new();
unsafe {
resizer.set_cpu_extensions(cpu_extensions);
}
let new_height = get_new_height(&image, NEW_BIG_WIDTH);
let mut result = Image::new(NEW_BIG_WIDTH, new_height, image.pixel_type());
resizer
.resize(&image, &mut result, &ResizeOptions::new().use_alpha(false))
.resize(
&image,
&mut result,
&ResizeOptions::new().resize_alg(resize_alg).use_alpha(false),
)
.unwrap();
let alg_name = match resize_alg {
@@ -819,29 +823,23 @@ mod not_u8x4 {
let mut src_buf = [0, 0, 0, 0, 255, 0, 0, 0, 0];
let src_image = Image::from_slice_u8(3, 3, &mut src_buf, PixelType::U8).unwrap();
let mut dst_image = Image::new(1, 1, PixelType::U8);
let mut resizer = Resizer::new(ResizeAlg::Convolution(FilterType::Box));
let mut resizer = Resizer::new();
let options = ResizeOptions::new().resize_alg(ResizeAlg::Convolution(FilterType::Box));
// Resize without cropping
resizer.resize(&src_image, &mut dst_image, None).unwrap();
resizer
.resize(&src_image, &mut dst_image, &options)
.unwrap();
assert_eq!(dst_image.buffer()[0], (255.0f32 / 9.0).round() as u8);
// Resize with fractional cropping
resizer
.resize(
&src_image,
&mut dst_image,
&ResizeOptions::new().crop(0.5, 0.5, 2., 2.),
)
.resize(&src_image, &mut dst_image, &options.crop(0.5, 0.5, 2., 2.))
.unwrap();
assert_eq!(dst_image.buffer()[0], (255.0f32 / 4.0).round() as u8);
// Resize with integer cropping
resizer
.resize(
&src_image,
&mut dst_image,
&ResizeOptions::new().crop(1., 1., 1., 1.),
)
.resize(&src_image, &mut dst_image, &options.crop(1., 1., 1., 1.))
.unwrap();
assert_eq!(dst_image.buffer()[0], 255);
}
@@ -858,11 +856,11 @@ mod u8x4 {
#[test]
fn invalid_crop_box() {
let mut resizer = Resizer::new(ResizeAlg::Nearest);
let mut resizer = Resizer::new();
let src_image = Image::new(1, 1, P::pixel_type());
let mut dst_image = Image::new(2, 2, P::pixel_type());
let mut options = ResizeOptions::new();
let mut options = ResizeOptions::new().resize_alg(ResizeAlg::Nearest);
for (left, top) in [(1., 0.), (0., 1.)] {
options = options.crop(left, top, 1., 1.);
@@ -1038,7 +1036,7 @@ mod u8x4 {
let mut dst_image = Image::new(1279, 1280, PixelType::U8x4);
let mut resizer = Resizer::new(ResizeAlg::Convolution(FilterType::Lanczos3));
let mut resizer = Resizer::new();
let mut cpu_extensions_vec = vec![CpuExtensions::None];
#[cfg(target_arch = "x86_64")]