mirror of
https://github.com/Cykooz/fast_image_resize.git
synced 2026-10-08 01:11:09 +00:00
- Added method SrcImageView.set_crop_box_to_fit_dst_size().
- Fixed out-of-bounds error during resize with cropping. - Refactored `ImageData`.
This commit is contained in:
@@ -1,5 +1,11 @@
|
||||
## [Unreleased] - ReleaseDate
|
||||
|
||||
- Added method `SrcImageView.set_crop_box_to_fit_dst_size()`.
|
||||
- Fixed out-of-bounds error during resize with cropping.
|
||||
- Refactored `ImageData`.
|
||||
- Added methods: `from_vec_u32()`, `from_vec_u8()`, `from_slice_u32()`,
|
||||
`from_slice_u8()`.
|
||||
- Removed methods: `from_buffer()`, `from_pixels()`.
|
||||
|
||||
## [0.2.0] - 2021-08-02
|
||||
|
||||
|
||||
Generated
+70
-41
@@ -21,10 +21,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e"
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.42"
|
||||
name = "ahash"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "595d3cfa7a60d4555cb5067b99f07142a08ea778de5cf993f7b75c7d8fabc486"
|
||||
checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28ae2b3dec75a406790005a200b1bd89785afc02517a00ca99ecfe093ee9e6cf"
|
||||
|
||||
[[package]]
|
||||
name = "argh"
|
||||
@@ -69,9 +80,9 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
@@ -177,9 +188,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.0"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
|
||||
checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-epoch",
|
||||
@@ -337,11 +348,11 @@ checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
||||
|
||||
[[package]]
|
||||
name = "fallible_collections"
|
||||
version = "0.4.2"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ad9169582543d2cfe9961be1e9eaf4fc42f9aa3483f7c485717b8dde36466ea"
|
||||
checksum = "eaefd4190151d458f16f0793d3452d7f13aeb3701566a4cefc4c37598876cc00"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
"hashbrown 0.11.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -389,9 +400,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "git2"
|
||||
version = "0.13.20"
|
||||
version = "0.13.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9831e983241f8c5591ed53f17d874833e2fa82cac2625f3888c50cbfe136cba"
|
||||
checksum = "659cd14835e75b64d9dba5b660463506763cf0aa6cb640aeeb0e98d841093490"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
@@ -429,7 +440,16 @@ version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"ahash 0.4.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
||||
dependencies = [
|
||||
"ahash 0.7.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -438,7 +458,7 @@ version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d99cf782f0dc4372d26846bec3de7804ceb5df083c2d4462c0b8d2330e894fa8"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
"hashbrown 0.9.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -500,15 +520,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.7"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
|
||||
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.22"
|
||||
version = "0.1.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "972f5ae5d1cb9c6ae417789196c803205313edde988685da5e3aae0827b9e7fd"
|
||||
checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@@ -530,15 +550,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.98"
|
||||
version = "0.2.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790"
|
||||
checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21"
|
||||
|
||||
[[package]]
|
||||
name = "libgit2-sys"
|
||||
version = "0.12.21+1.1.0"
|
||||
version = "0.12.22+1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86271bacd72b2b9e854c3dcfb82efd538f15f870e4c11af66900effb462f6825"
|
||||
checksum = "89c53ac117c44f7042ad8d8f5681378dfbc6010e49ec2c0d1f11dfedc7a4a1c3"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
@@ -589,15 +609,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "matches"
|
||||
version = "0.1.8"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
|
||||
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.4.0"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
|
||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
@@ -718,6 +738,12 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
|
||||
|
||||
[[package]]
|
||||
name = "open"
|
||||
version = "1.7.1"
|
||||
@@ -874,9 +900,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.9"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee"
|
||||
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
@@ -960,18 +986,18 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.126"
|
||||
version = "1.0.129"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
|
||||
checksum = "d1f72836d2aa753853178eda473a3b9d8e4eefdaf20523b919677e6de489f8f1"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.126"
|
||||
version = "1.0.129"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
|
||||
checksum = "e57ae87ad533d9a56427558b516d0adac283614e347abf85b0dc0cbbf0a249f3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -980,9 +1006,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.65"
|
||||
version = "1.0.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28c5e91e4240b46c4c19219d6cc84784444326131a4210f496f948d5cc827a29"
|
||||
checksum = "336b10da19a12ad094b59d870ebde26a45402e5b470add4b5fd03c5048a32127"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
@@ -1023,9 +1049,9 @@ checksum = "3bdb25a4593d6656239319426f4025f7a658157e25e89f0e0319d7516d46042d"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.74"
|
||||
version = "1.0.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c"
|
||||
checksum = "b7f58f7e8eaa0009c5fec437aabf511bd9933e4b2d7407bd05273c01a8906ea7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1118,12 +1144,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.5"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eeb8be209bb1c96b7c177c7420d26e04eccacb0eeae6b980e35fcb74678107e0"
|
||||
dependencies = [
|
||||
"matches",
|
||||
]
|
||||
checksum = "246f4c42e67e7a4e3c6106ff716a5d067d4132a642840b242e357e468a2a0085"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
@@ -1170,6 +1193,12 @@ version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.2+wasi-snapshot-preview1"
|
||||
|
||||
@@ -21,7 +21,7 @@ Environment:
|
||||
- RAM: DDR4 3000 MHz
|
||||
- Ubuntu 20.04 (linux 5.8)
|
||||
- Rust 1.54
|
||||
- fast_image_resize = "0.1"
|
||||
- fast_image_resize = "0.3"
|
||||
- glassbench = "0.3.0"
|
||||
|
||||
Other Rust libraries used to compare of resizing speed:
|
||||
@@ -45,21 +45,21 @@ Pipeline:
|
||||
|
||||
| | Nearest | Bilinear | CatmullRom | Lanczos3 |
|
||||
|------------|:-------:|:--------:|:----------:|:--------:|
|
||||
| image | 105.194 | 198.359 | 289.810 | 381.861 |
|
||||
| resize | 16.186 | 71.964 | 132.501 | 192.672 |
|
||||
| fir rust | 0.476 | 55.284 | 84.732 | 117.519 |
|
||||
| fir sse4.1 | - | 11.848 | 17.864 | 25.978 |
|
||||
| fir avx2 | - | 8.753 | 12.569 | 18.112 |
|
||||
| image | 106.303 | 199.011 | 291.423 | 382.793 |
|
||||
| resize | 16.099 | 71.947 | 132.481 | 205.961 |
|
||||
| fir rust | 0.478 | 55.376 | 84.567 | 117.269 |
|
||||
| fir sse4.1 | - | 11.847 | 17.823 | 25.459 |
|
||||
| fir avx2 | - | 8.598 | 11.864 | 17.549 |
|
||||
|
||||
Compiled with `rustflags = ["-C", "target-cpu=native"]`
|
||||
|
||||
| | Nearest | Bilinear | CatmullRom | Lanczos3 |
|
||||
|------------|:-------:|:--------:|:----------:|:--------:|
|
||||
| image | 91.138 | 182.251 | 279.838 | 380.956 |
|
||||
| resize | 15.967 | 62.125 | 114.870 | 168.013 |
|
||||
| fir rust | 0.467 | 56.376 | 61.565 | 85.433 |
|
||||
| fir sse4.1 | - | 11.229 | 16.503 | 23.465 |
|
||||
| fir avx2 | - | 8.464 | 11.602 | 17.076 |
|
||||
| image | 91.787 | 182.502 | 282.821 | 385.492 |
|
||||
| resize | 15.908 | 62.011 | 114.741 | 167.815 |
|
||||
| fir rust | 0.471 | 56.330 | 61.589 | 85.443 |
|
||||
| fir sse4.1 | - | 11.204 | 16.510 | 23.442 |
|
||||
| fir avx2 | - | 8.402 | 11.550 | 16.987 |
|
||||
|
||||
### Resize RGBA image 4928x3279 => 852x567
|
||||
|
||||
@@ -72,23 +72,25 @@ Pipeline:
|
||||
|
||||
| | Nearest | Bilinear | CatmullRom | Lanczos3 |
|
||||
|------------|:-------:|:--------:|:----------:|:--------:|
|
||||
| image | 101.499 | 216.029 | 335.151 | 455.582 |
|
||||
| resize | 19.671 | 85.199 | 155.205 | 224.660 |
|
||||
| fir rust | 13.583 | 67.031 | 94.816 | 124.344 |
|
||||
| fir sse4.1 | 12.012 | 23.370 | 29.345 | 36.925 |
|
||||
| fir avx2 | 6.893 | 15.162 | 18.959 | 24.518 |
|
||||
| image | 102.564 | 205.981 | 309.851 | 423.252 |
|
||||
| resize | 19.003 | 92.075 | 169.876 | 247.993 |
|
||||
| fir rust | 13.619 | 67.097 | 97.157 | 125.865 |
|
||||
| fir sse4.1 | 12.182 | 23.555 | 29.506 | 37.118 |
|
||||
| fir avx2 | 6.931 | 15.052 | 18.391 | 23.812 |
|
||||
|
||||
Compiled with `rustflags = ["-C", "target-cpu=native"]`
|
||||
|
||||
| | Nearest | Bilinear | CatmullRom | Lanczos3 |
|
||||
|------------|:-------:|:--------:|:----------:|:--------:|
|
||||
| image | 90.750 | 186.545 | 284.383 | 392.403 |
|
||||
| resize | 19.918 | 69.129 | 130.433 | 191.987 |
|
||||
| fir rust | 9.957 | 68.817 | 76.454 | 103.521 |
|
||||
| fir sse4.1 | 7.865 | 18.407 | 23.586 | 30.649 |
|
||||
| fir avx2 | 6.882 | 14.847 | 18.026 | 23.450 |
|
||||
| image | 90.421 | 193.379 | 306.635 | 422.674 |
|
||||
| resize | 19.572 | 69.091 | 130.327 | 192.235 |
|
||||
| fir rust | 9.987 | 69.005 | 76.551 | 103.646 |
|
||||
| fir sse4.1 | 7.860 | 18.375 | 23.601 | 30.603 |
|
||||
| fir avx2 | 6.897 | 14.907 | 18.034 | 23.677 |
|
||||
|
||||
## Example
|
||||
## Examples
|
||||
|
||||
### Resize image
|
||||
|
||||
```rust
|
||||
use std::io::BufWriter;
|
||||
@@ -109,38 +111,36 @@ fn resize_image_example() {
|
||||
.unwrap();
|
||||
let width = NonZeroU32::new(img.width()).unwrap();
|
||||
let height = NonZeroU32::new(img.height()).unwrap();
|
||||
let src_buffer = img.to_rgb8();
|
||||
let mut src_image = fr::ImageData::from_vec_u8(
|
||||
width,
|
||||
height,
|
||||
img.to_rgba8().into_raw(),
|
||||
fr::PixelType::U8x4,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Create immutable view of source image data
|
||||
let src_view =
|
||||
fr::SrcImageView::from_buffer(
|
||||
width,
|
||||
height,
|
||||
src_buffer.as_raw(),
|
||||
fr::PixelType::U8x4
|
||||
)
|
||||
// Create MulDiv instance
|
||||
let alpha_mul_div: fr::MulDiv = Default::default();
|
||||
// Multiple RGB channels of source image by alpha channel
|
||||
alpha_mul_div
|
||||
.multiply_alpha_inplace(&mut src_image.dst_view())
|
||||
.unwrap();
|
||||
|
||||
// Create wrapper that own data of destination image
|
||||
let dst_width = NonZeroU32::new(1024).unwrap();
|
||||
let dst_height = NonZeroU32::new(768).unwrap();
|
||||
let mut dst_image = fr::ImageData::new(
|
||||
dst_width,
|
||||
dst_height,
|
||||
src_view.pixel_type()
|
||||
);
|
||||
let mut dst_image = fr::ImageData::new(dst_width, dst_height, src_image.pixel_type());
|
||||
|
||||
// Get mutable view of destination image data
|
||||
let mut dst_view = dst_image.dst_view();
|
||||
|
||||
// Create Resizer instance and resize source image
|
||||
// Create Resizer instance and resize source image
|
||||
// into buffer of destination image
|
||||
let mut resizer = fr::Resizer::new(
|
||||
fr::ResizeAlg::Convolution(
|
||||
fr::FilterType::Lanczos3
|
||||
)
|
||||
);
|
||||
resizer.resize(&src_view, &mut dst_view);
|
||||
let mut resizer = fr::Resizer::new(fr::ResizeAlg::Convolution(fr::FilterType::Lanczos3));
|
||||
resizer.resize(&src_image.src_view(), &mut dst_view);
|
||||
|
||||
// Divide RGB channels of destination image by alpha
|
||||
alpha_mul_div.divide_alpha_inplace(&mut dst_view).unwrap();
|
||||
|
||||
// Write destination image as PNG-file
|
||||
let mut result_buf = BufWriter::new(Vec::new());
|
||||
@@ -150,8 +150,22 @@ fn resize_image_example() {
|
||||
dst_image.get_buffer(),
|
||||
dst_width.get(),
|
||||
dst_height.get(),
|
||||
ColorType::Rgb8,
|
||||
ColorType::Rgba8,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
```
|
||||
|
||||
### Change CPU extensions used by resizer
|
||||
|
||||
```rust
|
||||
use fast_image_resize as fr;
|
||||
|
||||
fn main() {
|
||||
let mut resizer = fr::Resizer::new(fr::ResizeAlg::Convolution(fr::FilterType::Lanczos3));
|
||||
unsafe {
|
||||
resizer.set_cpu_extensions(fr::CpuExtensions::Sse4_1);
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
@@ -10,10 +10,10 @@ const fn p(r: u8, g: u8, b: u8, a: u8) -> u32 {
|
||||
|
||||
// Multiplies by alpha
|
||||
|
||||
fn get_src_image(width: NonZeroU32, height: NonZeroU32, pixel: u32) -> ImageData<Vec<u32>> {
|
||||
fn get_src_image(width: NonZeroU32, height: NonZeroU32, pixel: u32) -> ImageData {
|
||||
let buf_size = (width.get() * height.get()) as usize;
|
||||
let buffer = vec![pixel; buf_size];
|
||||
ImageData::from_pixels(width, height, buffer, PixelType::U8x4).unwrap()
|
||||
ImageData::from_vec_u32(width, height, buffer, PixelType::U8x4).unwrap()
|
||||
}
|
||||
|
||||
fn multiplies_alpha_avx2(bench: &mut Bench) {
|
||||
|
||||
@@ -76,15 +76,10 @@ pub fn bench_downscale_rgb(bench: &mut Bench) {
|
||||
};
|
||||
for alg_name in alg_names {
|
||||
let src_rgba_image = utils::get_big_rgba_image();
|
||||
let buf: Vec<u32> = src_rgba_image
|
||||
.as_raw()
|
||||
.chunks_exact(4)
|
||||
.map(|p| u32::from_le_bytes([p[0], p[1], p[2], p[3]]))
|
||||
.collect();
|
||||
let src_image_data = ImageData::from_pixels(
|
||||
let src_image_data = ImageData::from_vec_u8(
|
||||
NonZeroU32::new(src_image.width()).unwrap(),
|
||||
NonZeroU32::new(src_image.height()).unwrap(),
|
||||
buf,
|
||||
src_rgba_image.into_raw(),
|
||||
PixelType::U8x4,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -83,15 +83,10 @@ pub fn bench_downscale_rgba(bench: &mut Bench) {
|
||||
"Lanczos3" => ResizeAlg::Convolution(FilterType::Lanczos3),
|
||||
_ => return,
|
||||
};
|
||||
let buf: Vec<u32> = src_image
|
||||
.as_raw()
|
||||
.chunks_exact(4)
|
||||
.map(|p| u32::from_le_bytes([p[0], p[1], p[2], p[3]]))
|
||||
.collect();
|
||||
let src_image_data = ImageData::from_pixels(
|
||||
let src_image_data = ImageData::from_vec_u8(
|
||||
NonZeroU32::new(src_image.width()).unwrap(),
|
||||
NonZeroU32::new(src_image.height()).unwrap(),
|
||||
buf,
|
||||
src_image.into_raw(),
|
||||
PixelType::U8x4,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
+6
-16
@@ -13,37 +13,27 @@ const NEW_HEIGHT: u32 = 567;
|
||||
const NEW_BIG_WIDTH: u32 = 4928;
|
||||
const NEW_BIG_HEIGHT: u32 = 3279;
|
||||
|
||||
fn get_big_source_image() -> ImageData<Vec<u32>> {
|
||||
fn get_big_source_image() -> ImageData {
|
||||
let img = utils::get_big_rgba_image();
|
||||
let width = img.width();
|
||||
let height = img.height();
|
||||
let buf = img
|
||||
.as_raw()
|
||||
.chunks_exact(4)
|
||||
.map(|p| u32::from_le_bytes([p[0], p[1], p[2], p[3]]))
|
||||
.collect();
|
||||
ImageData::from_pixels(
|
||||
ImageData::from_vec_u8(
|
||||
NonZeroU32::new(width).unwrap(),
|
||||
NonZeroU32::new(height).unwrap(),
|
||||
buf,
|
||||
img.into_raw(),
|
||||
PixelType::U8x4,
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn get_small_source_image() -> ImageData<Vec<u32>> {
|
||||
fn get_small_source_image() -> ImageData {
|
||||
let img = utils::get_small_rgba_image();
|
||||
let width = img.width();
|
||||
let height = img.height();
|
||||
let buf = img
|
||||
.as_raw()
|
||||
.chunks_exact(4)
|
||||
.map(|p| u32::from_le_bytes([p[0], p[1], p[2], p[3]]))
|
||||
.collect();
|
||||
ImageData::from_pixels(
|
||||
ImageData::from_vec_u8(
|
||||
NonZeroU32::new(width).unwrap(),
|
||||
NonZeroU32::new(height).unwrap(),
|
||||
buf,
|
||||
img.into_raw(),
|
||||
PixelType::U8x4,
|
||||
)
|
||||
.unwrap()
|
||||
|
||||
+105
-52
@@ -1,30 +1,110 @@
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
use crate::{DstImageView, InvalidBufferSizeError, PixelType, SrcImageView};
|
||||
use crate::{DstImageView, ImageBufferError, InvalidBufferSizeError, PixelType, SrcImageView};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ImageData<T: AsRef<[u32]>> {
|
||||
#[derive(Debug)]
|
||||
enum PixelsContainer<'a> {
|
||||
Mut(&'a mut [u32]),
|
||||
VecU32(Vec<u32>),
|
||||
VecU8(Vec<u8>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ImageData<'a> {
|
||||
width: NonZeroU32,
|
||||
height: NonZeroU32,
|
||||
pixels: T,
|
||||
pixels: PixelsContainer<'a>,
|
||||
pixel_type: PixelType,
|
||||
}
|
||||
|
||||
impl<T: AsRef<[u32]>> ImageData<T> {
|
||||
pub fn from_pixels(
|
||||
impl<'a> ImageData<'a> {
|
||||
pub fn new(width: NonZeroU32, height: NonZeroU32, pixel_type: PixelType) -> Self {
|
||||
let size = (width.get() * height.get()) as usize;
|
||||
let pixels = vec![0; size];
|
||||
Self {
|
||||
width,
|
||||
height,
|
||||
pixels: PixelsContainer::VecU32(pixels),
|
||||
pixel_type,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_vec_u32(
|
||||
width: NonZeroU32,
|
||||
height: NonZeroU32,
|
||||
pixels: T,
|
||||
pixels: Vec<u32>,
|
||||
pixel_type: PixelType,
|
||||
) -> Result<Self, InvalidBufferSizeError> {
|
||||
let size = (width.get() * height.get()) as usize;
|
||||
if pixels.as_ref().len() != size {
|
||||
if pixels.len() != size {
|
||||
return Err(InvalidBufferSizeError);
|
||||
}
|
||||
Ok(Self {
|
||||
width,
|
||||
height,
|
||||
pixels,
|
||||
pixels: PixelsContainer::VecU32(pixels),
|
||||
pixel_type,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_vec_u8(
|
||||
width: NonZeroU32,
|
||||
height: NonZeroU32,
|
||||
mut pixels: Vec<u8>,
|
||||
pixel_type: PixelType,
|
||||
) -> Result<Self, ImageBufferError> {
|
||||
let size = (width.get() * height.get()) as usize * 4;
|
||||
if pixels.len() != size {
|
||||
return Err(ImageBufferError::InvalidBufferSize);
|
||||
}
|
||||
let (head, _, _) = unsafe { &pixels.align_to_mut::<u32>() };
|
||||
if !head.is_empty() {
|
||||
return Err(ImageBufferError::InvalidBufferAlignment);
|
||||
}
|
||||
Ok(Self {
|
||||
width,
|
||||
height,
|
||||
pixels: PixelsContainer::VecU8(pixels),
|
||||
pixel_type,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_slice_u32(
|
||||
width: NonZeroU32,
|
||||
height: NonZeroU32,
|
||||
pixels: &'a mut [u32],
|
||||
pixel_type: PixelType,
|
||||
) -> Result<Self, InvalidBufferSizeError> {
|
||||
let size = (width.get() * height.get()) as usize;
|
||||
if pixels.len() != size {
|
||||
return Err(InvalidBufferSizeError);
|
||||
}
|
||||
Ok(Self {
|
||||
width,
|
||||
height,
|
||||
pixels: PixelsContainer::Mut(pixels),
|
||||
pixel_type,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_slice_u8(
|
||||
width: NonZeroU32,
|
||||
height: NonZeroU32,
|
||||
buffer: &'a mut [u8],
|
||||
pixel_type: PixelType,
|
||||
) -> Result<Self, ImageBufferError> {
|
||||
let size = (width.get() * height.get()) as usize * 4;
|
||||
if buffer.len() != size {
|
||||
return Err(ImageBufferError::InvalidBufferSize);
|
||||
}
|
||||
let (head, pixels, _) = unsafe { buffer.align_to_mut::<u32>() };
|
||||
if !head.is_empty() {
|
||||
return Err(ImageBufferError::InvalidBufferAlignment);
|
||||
}
|
||||
Ok(Self {
|
||||
width,
|
||||
height,
|
||||
pixels: PixelsContainer::Mut(pixels),
|
||||
pixel_type,
|
||||
})
|
||||
}
|
||||
@@ -46,64 +126,37 @@ impl<T: AsRef<[u32]>> ImageData<T> {
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_pixels(&self) -> &[u32] {
|
||||
self.pixels.as_ref()
|
||||
match &self.pixels {
|
||||
PixelsContainer::Mut(p) => p,
|
||||
PixelsContainer::VecU32(v) => v,
|
||||
PixelsContainer::VecU8(v) => unsafe { v.align_to::<u32>().1 },
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_buffer(&self) -> &[u8] {
|
||||
let (_, buffer, _) = unsafe { self.pixels.as_ref().align_to::<u8>() };
|
||||
let pixels = self.get_pixels();
|
||||
let (_, buffer, _) = unsafe { pixels.align_to::<u8>() };
|
||||
buffer
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn src_view(&self) -> SrcImageView {
|
||||
let pixels = self.pixels.as_ref();
|
||||
let pixels = self.get_pixels();
|
||||
let rows = pixels.chunks(self.width.get() as usize).collect();
|
||||
SrcImageView::from_rows(self.width, self.height, rows, self.pixel_type).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<[u32]> + AsMut<[u32]>> ImageData<T> {
|
||||
#[inline(always)]
|
||||
pub fn dst_view(&mut self) -> DstImageView {
|
||||
let pixels = self.pixels.as_mut();
|
||||
let rows = pixels.chunks_mut(self.width.get() as usize).collect();
|
||||
let rows = match &mut self.pixels {
|
||||
PixelsContainer::Mut(p) => p.chunks_mut(self.width.get() as usize).collect(),
|
||||
PixelsContainer::VecU32(v) => v.chunks_mut(self.width.get() as usize).collect(),
|
||||
PixelsContainer::VecU8(v) => {
|
||||
let p = unsafe { v.align_to_mut::<u32>().1 };
|
||||
p.chunks_mut(self.width.get() as usize).collect()
|
||||
}
|
||||
};
|
||||
DstImageView::from_rows(self.width, self.height, rows, self.pixel_type).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl ImageData<Vec<u32>> {
|
||||
pub fn new(width: NonZeroU32, height: NonZeroU32, pixel_type: PixelType) -> Self {
|
||||
let size = (width.get() * height.get()) as usize;
|
||||
let pixels = vec![0; size];
|
||||
Self {
|
||||
width,
|
||||
height,
|
||||
pixels,
|
||||
pixel_type,
|
||||
}
|
||||
}
|
||||
|
||||
/// Copy content of given `buffer` into internal `Vec<u32>`
|
||||
pub fn from_buffer(
|
||||
width: NonZeroU32,
|
||||
height: NonZeroU32,
|
||||
buffer: &[u8],
|
||||
pixel_type: PixelType,
|
||||
) -> Result<Self, InvalidBufferSizeError> {
|
||||
let size = (width.get() * height.get()) as usize * 4;
|
||||
if buffer.len() != size {
|
||||
return Err(InvalidBufferSizeError);
|
||||
}
|
||||
let pixels = buffer
|
||||
.chunks_exact(4)
|
||||
.map(|p| u32::from_le_bytes([p[0], p[1], p[2], p[3]]))
|
||||
.collect();
|
||||
Ok(Self {
|
||||
width,
|
||||
height,
|
||||
pixels,
|
||||
pixel_type,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,6 +142,68 @@ impl<'a> SrcImageView<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set a crop box to resize the source image into the
|
||||
/// aspect ratio of destination image without distortions.
|
||||
///
|
||||
/// `centering` used to control the cropping position. Use (0.5, 0.5) for
|
||||
/// center cropping (e.g. if cropping the width, take 50% off
|
||||
/// of the left side, and therefore 50% off the right side).
|
||||
/// (0.0, 0.0) will crop from the top left corner (i.e. if
|
||||
/// cropping the width, take all of the crop off of the right
|
||||
/// side, and if cropping the height, take all of it off the
|
||||
/// bottom). (1.0, 0.0) will crop from the bottom left
|
||||
/// corner, etc. (i.e. if cropping the width, take all of the
|
||||
/// crop off the left side, and if cropping the height take
|
||||
/// none from the top, and therefore all off the bottom).
|
||||
pub fn set_crop_box_to_fit_dst_size(
|
||||
&mut self,
|
||||
dst_width: NonZeroU32,
|
||||
dst_height: NonZeroU32,
|
||||
centering: Option<(f32, f32)>,
|
||||
) {
|
||||
// This function based on code of ImageOps.fit() from Pillow package.
|
||||
// https://github.com/python-pillow/Pillow/blob/master/src/PIL/ImageOps.py
|
||||
let centering = if let Some((x, y)) = centering {
|
||||
(x.clamp(0.0, 1.0), y.clamp(0.0, 1.0))
|
||||
} else {
|
||||
(0.5, 0.5)
|
||||
};
|
||||
|
||||
// calculate aspect ratios
|
||||
let width = self.width.get() as f32;
|
||||
let height = self.height.get() as f32;
|
||||
let image_ratio = width / height;
|
||||
let required_ration = dst_width.get() as f32 / dst_height.get() as f32;
|
||||
|
||||
let crop_width;
|
||||
let crop_height;
|
||||
// figure out if the sides or top/bottom will be cropped off
|
||||
if (image_ratio - required_ration).abs() < f32::EPSILON {
|
||||
// The image is already the needed ratio
|
||||
crop_width = width;
|
||||
crop_height = height;
|
||||
} else if image_ratio >= required_ration {
|
||||
// The image is wider than what's needed, crop the sides
|
||||
crop_width = required_ration * height;
|
||||
crop_height = height;
|
||||
} else {
|
||||
// The image is taller than what's needed, crop the top and bottom
|
||||
crop_width = width;
|
||||
crop_height = width / required_ration;
|
||||
}
|
||||
|
||||
let crop_left = (width - crop_width) * centering.0;
|
||||
let crop_top = (height - crop_height) * centering.1;
|
||||
|
||||
self.set_crop_box(CropBox {
|
||||
left: crop_left.round() as u32,
|
||||
top: crop_top.round() as u32,
|
||||
width: NonZeroU32::new(crop_width.round() as u32).unwrap(),
|
||||
height: NonZeroU32::new(crop_height.round() as u32).unwrap(),
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_buffer(&self) -> Vec<u8> {
|
||||
let row_size = self.width.get() as usize;
|
||||
|
||||
+8
-8
@@ -147,13 +147,13 @@ fn get_temp_image_from_buffer(
|
||||
width: NonZeroU32,
|
||||
height: NonZeroU32,
|
||||
pixel_type: PixelType,
|
||||
) -> ImageData<&mut [u32]> {
|
||||
) -> ImageData {
|
||||
let buf_size = (width.get() * height.get()) as usize;
|
||||
if buffer.len() < buf_size {
|
||||
buffer.resize(buf_size, 0);
|
||||
}
|
||||
let pixels = &mut buffer[0..buf_size];
|
||||
ImageData::from_pixels(width, height, pixels, pixel_type).unwrap()
|
||||
ImageData::from_slice_u32(width, height, pixels, pixel_type).unwrap()
|
||||
}
|
||||
|
||||
fn resample_nearest(src_image: &SrcImageView, dst_image: &mut DstImageView) {
|
||||
@@ -221,12 +221,6 @@ fn resample_convolution(
|
||||
let y_first = vert_coeffs.bounds[0].start;
|
||||
|
||||
if need_vertical {
|
||||
// Shift bounds for vertical pass
|
||||
vert_coeffs
|
||||
.bounds
|
||||
.iter_mut()
|
||||
.for_each(|b| b.start -= y_first);
|
||||
|
||||
// Last used row in the source image
|
||||
let last_y_bound = vert_coeffs.bounds.last().unwrap();
|
||||
let y_last = last_y_bound.start + last_y_bound.size;
|
||||
@@ -244,6 +238,12 @@ fn resample_convolution(
|
||||
y_first,
|
||||
horiz_coeffs,
|
||||
);
|
||||
|
||||
// Shift bounds for vertical pass
|
||||
vert_coeffs
|
||||
.bounds
|
||||
.iter_mut()
|
||||
.for_each(|b| b.start -= y_first);
|
||||
resampler.vert_convolution(&temp_image.src_view(), dst_image, vert_coeffs);
|
||||
} else {
|
||||
resampler.horiz_convolution(src_image, dst_image, y_first, horiz_coeffs);
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
use std::io::BufWriter;
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
use image::codecs::png::PngEncoder;
|
||||
use image::io::Reader as ImageReader;
|
||||
use image::{ColorType, GenericImageView};
|
||||
|
||||
use fast_image_resize as fr;
|
||||
|
||||
#[test]
|
||||
fn resize_image_example() {
|
||||
// Read source image from file
|
||||
let img = ImageReader::open("./data/nasa-4928x3279.png")
|
||||
.unwrap()
|
||||
.decode()
|
||||
.unwrap();
|
||||
let width = NonZeroU32::new(img.width()).unwrap();
|
||||
let height = NonZeroU32::new(img.height()).unwrap();
|
||||
let mut src_image = fr::ImageData::from_vec_u8(
|
||||
width,
|
||||
height,
|
||||
img.to_rgba8().into_raw(),
|
||||
fr::PixelType::U8x4,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Create MulDiv instance
|
||||
let alpha_mul_div: fr::MulDiv = Default::default();
|
||||
// Multiple RGB channels of source image by alpha channel
|
||||
alpha_mul_div
|
||||
.multiply_alpha_inplace(&mut src_image.dst_view())
|
||||
.unwrap();
|
||||
|
||||
// Create wrapper that own data of destination image
|
||||
let dst_width = NonZeroU32::new(1024).unwrap();
|
||||
let dst_height = NonZeroU32::new(768).unwrap();
|
||||
let mut dst_image = fr::ImageData::new(dst_width, dst_height, src_image.pixel_type());
|
||||
|
||||
// Get mutable view of destination image data
|
||||
let mut dst_view = dst_image.dst_view();
|
||||
|
||||
// Create Resizer instance and resize source image
|
||||
// into buffer of destination image
|
||||
let mut resizer = fr::Resizer::new(fr::ResizeAlg::Convolution(fr::FilterType::Lanczos3));
|
||||
resizer.resize(&src_image.src_view(), &mut dst_view);
|
||||
|
||||
// Divide RGB channels of destination image by alpha
|
||||
alpha_mul_div.divide_alpha_inplace(&mut dst_view).unwrap();
|
||||
|
||||
// Write destination image as PNG-file
|
||||
let mut result_buf = BufWriter::new(Vec::new());
|
||||
let encoder = PngEncoder::new(&mut result_buf);
|
||||
encoder
|
||||
.encode(
|
||||
dst_image.get_buffer(),
|
||||
dst_width.get(),
|
||||
dst_height.get(),
|
||||
ColorType::Rgba8,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut resizer = fr::Resizer::new(fr::ResizeAlg::Convolution(fr::FilterType::Lanczos3));
|
||||
unsafe {
|
||||
resizer.set_cpu_extensions(fr::CpuExtensions::Sse4_1);
|
||||
}
|
||||
// ...
|
||||
}
|
||||
+34
-17
@@ -5,38 +5,37 @@ use image::codecs::png::PngEncoder;
|
||||
use image::io::Reader as ImageReader;
|
||||
use image::{ColorType, GenericImageView};
|
||||
|
||||
use fast_image_resize::ImageData;
|
||||
use fast_image_resize::{CpuExtensions, FilterType, PixelType, ResizeAlg, Resizer, SrcImageView};
|
||||
use fast_image_resize::{
|
||||
CpuExtensions, FilterType, ImageData, PixelType, ResizeAlg, Resizer, SrcImageView,
|
||||
};
|
||||
|
||||
fn get_source_image() -> ImageData<Vec<u32>> {
|
||||
let img = ImageReader::open("./data/nasa-4928x3279.png")
|
||||
fn get_source_image() -> ImageData<'static> {
|
||||
let img = ImageReader::open("/home/cykooz/t.png")
|
||||
.unwrap()
|
||||
.decode()
|
||||
.unwrap();
|
||||
let width = img.width();
|
||||
let height = img.height();
|
||||
let rgba = img.to_rgba8();
|
||||
ImageData::from_buffer(
|
||||
ImageData::from_vec_u8(
|
||||
NonZeroU32::new(width).unwrap(),
|
||||
NonZeroU32::new(height).unwrap(),
|
||||
rgba.as_raw(),
|
||||
img.to_rgba8().into_raw(),
|
||||
PixelType::U8x4,
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn get_small_source_image() -> ImageData<Vec<u32>> {
|
||||
fn get_small_source_image() -> ImageData<'static> {
|
||||
let img = ImageReader::open("./data/nasa-852x567.png")
|
||||
.unwrap()
|
||||
.decode()
|
||||
.unwrap();
|
||||
let width = img.width();
|
||||
let height = img.height();
|
||||
let rgba = img.to_rgba8();
|
||||
ImageData::from_buffer(
|
||||
ImageData::from_vec_u8(
|
||||
NonZeroU32::new(width).unwrap(),
|
||||
NonZeroU32::new(height).unwrap(),
|
||||
rgba.as_raw(),
|
||||
img.to_rgba8().into_raw(),
|
||||
PixelType::U8x4,
|
||||
)
|
||||
.unwrap()
|
||||
@@ -65,7 +64,7 @@ fn save_result(image: &SrcImageView, name: &str) {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resample_wo_simd_lanczos3_test() {
|
||||
fn resize_wo_simd_lanczos3_test() {
|
||||
let image = get_source_image();
|
||||
let mut resizer = Resizer::new(ResizeAlg::Convolution(FilterType::Lanczos3));
|
||||
unsafe {
|
||||
@@ -82,7 +81,7 @@ fn resample_wo_simd_lanczos3_test() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resample_sse4_lanczos3_test() {
|
||||
fn resize_sse4_lanczos3_test() {
|
||||
let image = get_source_image();
|
||||
let mut resizer = Resizer::new(ResizeAlg::Convolution(FilterType::Lanczos3));
|
||||
unsafe {
|
||||
@@ -99,7 +98,7 @@ fn resample_sse4_lanczos3_test() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resample_avx2_lanczos3_test() {
|
||||
fn resize_avx2_lanczos3_test() {
|
||||
let image = get_source_image();
|
||||
let mut resizer = Resizer::new(ResizeAlg::Convolution(FilterType::Lanczos3));
|
||||
unsafe {
|
||||
@@ -116,7 +115,7 @@ fn resample_avx2_lanczos3_test() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resample_avx2_lanczos3_upscale_test() {
|
||||
fn resize_avx2_lanczos3_upscale_test() {
|
||||
let image = get_small_source_image();
|
||||
let mut resizer = Resizer::new(ResizeAlg::Convolution(FilterType::Lanczos3));
|
||||
unsafe {
|
||||
@@ -133,7 +132,7 @@ fn resample_avx2_lanczos3_upscale_test() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resample_nearest_test() {
|
||||
fn resize_nearest_test() {
|
||||
let image = get_source_image();
|
||||
let mut resizer = Resizer::new(ResizeAlg::Nearest);
|
||||
unsafe {
|
||||
@@ -150,7 +149,7 @@ fn resample_nearest_test() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resample_super_sampling_test() {
|
||||
fn resize_super_sampling_test() {
|
||||
let image = get_source_image();
|
||||
let mut resizer = Resizer::new(ResizeAlg::SuperSampling(FilterType::Lanczos3, 2));
|
||||
unsafe {
|
||||
@@ -165,3 +164,21 @@ fn resample_super_sampling_test() {
|
||||
resizer.resize(&image.src_view(), &mut result.dst_view());
|
||||
save_result(&result.src_view(), "super_sampling_avx2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resize_with_cropping() {
|
||||
let src_image = get_source_image();
|
||||
let mut resizer = Resizer::new(ResizeAlg::Convolution(FilterType::Lanczos3));
|
||||
unsafe {
|
||||
resizer.set_cpu_extensions(CpuExtensions::None);
|
||||
}
|
||||
let mut dst_image = ImageData::new(
|
||||
NonZeroU32::new(256).unwrap(),
|
||||
NonZeroU32::new(256).unwrap(),
|
||||
src_image.pixel_type(),
|
||||
);
|
||||
let mut src_view = src_image.src_view();
|
||||
src_view.set_crop_box_to_fit_dst_size(dst_image.width(), dst_image.height(), None);
|
||||
resizer.resize(&src_view, &mut dst_image.dst_view());
|
||||
save_result(&dst_image.src_view(), "cropping_lanczos3_avx2");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user