- Trait Pixel renamed into PixelExt and changed.

- All pixel types (`U8`, `U8x2`, ...) replaced by type aliases for new generic structure `Pixel`. Use method `new()` to create instance of one pixel.
- Added module `color` for working with colorspace and gamma.
This commit is contained in:
Kirill Kuzminykh
2022-10-07 20:39:21 +04:00
parent 39f7841030
commit e3b64bf7b1
42 changed files with 585 additions and 408 deletions
+14 -6
View File
@@ -5,17 +5,25 @@
- Breaking changes:
- Struct `ImageView` replaced by enum `DynamicImageView`.
- Struct `ImageViewMut` replaced by enum `DynamicImageViewMut`.
- Trait `Pixel` changed:
- Associated type `ComponentsCount` renamed into `CountOfComponents`.
- Associated type `ComponentCountOfValues` renamed into `CountOfComponentValues`.
- Associated method `components_count` renamed into `count_of_components`.
- Associated method `component_count_of_values` renamed into `count_of_component_values`.
- Trait `Pixel` renamed into `PixelExt` and changed:
- associated type `ComponentsCount` renamed into `CountOfComponents`.
- associated type `ComponentCountOfValues` deleted.
- associated method `components_count` renamed into `count_of_components`.
- associated method `component_count_of_values` renamed into `count_of_component_values`.
- All pixel types (`U8`, `U8x2`, ...) replaced by type aliases for new
generic structure `Pixel`. Use method `new()` to create
instance of one pixel.
- Added module `color` for working with colorspace and gamma:
- Added mapper `SRGB_TO_RGB`. It is lazy static instance of `PixelComponentMapper` to
convert images from SRGB colorspace to linear RGB and back.
- Added mapper `GAMMA22_TO_LINEAR`. It is lazy static instance of `PixelComponentMapper`
to convert images with gamma 2.2 to linear colorspace and back.
- Added generic structs `ImageView` and `ImageViewMut`.
- Added module `color` for working with colorspace and gamma.
- Added functions `change_type_of_pixel_components` and
`change_type_of_pixel_components_dyn` to change type of pixel's
components in whole image.
- Added generic trait `IntoPixelComponent<Out: PixelComponent>`.
- Added generic structure `Pixel` for create all types of pixels.
### Example application
Generated
+60 -96
View File
@@ -51,9 +51,9 @@ checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602"
[[package]]
name = "argh"
version = "0.1.8"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7e7e4aa7e40747e023c0761dafcb42333a9517575bbf1241747f68dd3177a62"
checksum = "c375edecfd2074d5edcc31396860b6e54b6f928714d0e097b983053fac0cabe3"
dependencies = [
"argh_derive",
"argh_shared",
@@ -61,12 +61,12 @@ dependencies = [
[[package]]
name = "argh_derive"
version = "0.1.8"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69f2bd7ff6ed6414f4e5521bd509bae46454bbd513801767ced3f21a751ab4bc"
checksum = "aa013479b80109a1bf01a039412b0f0013d716f36921226d86c6709032fb7a03"
dependencies = [
"argh_shared",
"heck 0.3.3",
"heck",
"proc-macro2",
"quote",
"syn",
@@ -74,9 +74,9 @@ dependencies = [
[[package]]
name = "argh_shared"
version = "0.1.8"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47253b98986dafc7a3e1cf3259194f1f47ac61abb57a57f46ec09e48d004ecda"
checksum = "149f75bbec1827618262e0855a68f0f9a7f2edc13faebf33c4f16d6725edb6a9"
[[package]]
name = "atty"
@@ -176,26 +176,24 @@ dependencies = [
[[package]]
name = "clap"
version = "3.2.21"
version = "4.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ed5341b2301a26ab80be5cbdced622e80ed808483c52e45e3310a877d3b37d7"
checksum = "30607dd93c420c6f1f80b544be522a0238a7db35e6a12968d28910983fee0df0"
dependencies = [
"atty",
"bitflags",
"clap_derive",
"clap_lex",
"indexmap",
"once_cell",
"strsim",
"termcolor",
"textwrap",
]
[[package]]
name = "clap-verbosity-flag"
version = "1.0.1"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0636f9c040082f8e161555a305f8cec1a1c2828b3d981c812b8c39f4ac00c42c"
checksum = "23e2b6c3dcdb73299f48ae05b294da14e2f560b3ed2c09e742269eb1b22af231"
dependencies = [
"clap",
"log",
@@ -203,11 +201,11 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "3.2.18"
version = "4.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65"
checksum = "a4a307492e1a34939f79d3b6b9650bd2b971513cd775436bf2b78defeb5af00b"
dependencies = [
"heck 0.4.0",
"heck",
"proc-macro-error",
"proc-macro2",
"quote",
@@ -216,9 +214,9 @@ dependencies = [
[[package]]
name = "clap_lex"
version = "0.2.4"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8"
dependencies = [
"os_str_bytes",
]
@@ -302,15 +300,14 @@ dependencies = [
[[package]]
name = "crossbeam-epoch"
version = "0.9.10"
version = "0.9.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1"
checksum = "f916dfc5d356b0ed9dae65f1db9fc9770aa2851d2662b988ccf4fe3516e86348"
dependencies = [
"autocfg",
"cfg-if",
"crossbeam-utils",
"memoffset",
"once_cell",
"scopeguard",
]
@@ -326,12 +323,11 @@ dependencies = [
[[package]]
name = "crossbeam-utils"
version = "0.8.11"
version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc"
checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac"
dependencies = [
"cfg-if",
"once_cell",
]
[[package]]
@@ -431,9 +427,9 @@ checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
[[package]]
name = "env_logger"
version = "0.9.0"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
checksum = "c90bf5f19754d10198ccb95b70664fc925bd1fc090a0fd9a6ebc54acc8cd6272"
dependencies = [
"atty",
"humantime",
@@ -444,9 +440,9 @@ dependencies = [
[[package]]
name = "exr"
version = "1.5.0"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78c26a90d9dd411a3d119d6f55752fb4c134ca243250c32fb9cab7b2561638d2"
checksum = "c9a7880199e74c6d3fe45579df2f436c5913a71405494cb89d59234d86b47dc5"
dependencies = [
"bit_field",
"flume",
@@ -644,15 +640,6 @@ dependencies = [
"hashbrown 0.9.1",
]
[[package]]
name = "heck"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "heck"
version = "0.4.0"
@@ -676,14 +663,13 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "iana-time-zone"
version = "0.1.48"
version = "0.1.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "237a0714f28b1ee39ccec0770ccb544eb02c9ef2c82bb096230eefcffa6468b0"
checksum = "fd911b35d940d2bd0bea0f9100068e5b97b51a1cbe13d13382f132e0365257a0"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"js-sys",
"once_cell",
"wasm-bindgen",
"winapi",
]
@@ -700,9 +686,9 @@ dependencies = [
[[package]]
name = "image"
version = "0.24.3"
version = "0.24.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e30ca2ecf7666107ff827a8e481de6a132a9b687ed3bb20bb1c144a36c00964"
checksum = "bd8e4fb07cf672b1642304e731ef8a6a4c7891d67bb4fd4f5ce58cd6ed86803c"
dependencies = [
"bytemuck",
"byteorder",
@@ -717,16 +703,6 @@ dependencies = [
"tiff",
]
[[package]]
name = "indexmap"
version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
dependencies = [
"autocfg",
"hashbrown 0.12.3",
]
[[package]]
name = "instant"
version = "0.1.12"
@@ -750,9 +726,9 @@ checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754"
[[package]]
name = "jobserver"
version = "0.1.24"
version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa"
checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b"
dependencies = [
"libc",
]
@@ -789,9 +765,9 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"
[[package]]
name = "libc"
version = "0.2.132"
version = "0.2.134"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5"
checksum = "329c933548736bc49fd575ee68c89e8be4d260064184389a5b77517cddd99ffb"
[[package]]
name = "libgit2-sys"
@@ -830,9 +806,9 @@ dependencies = [
[[package]]
name = "lock_api"
version = "0.4.8"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f80bf5aacaf25cbfc8210d1cfb718f2bf3b11c4c54e5afe36c236853a8ec390"
checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
dependencies = [
"autocfg",
"scopeguard",
@@ -864,9 +840,9 @@ dependencies = [
[[package]]
name = "minimad"
version = "0.9.0"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd37b2e65fbd459544194d8f52ed84027e031684335a062c708774c09d172b0b"
checksum = "277639f0198568f70f8fe4ab88a52a67c96bca12f27ba5c17a76acdcb8b45834"
dependencies = [
"once_cell",
]
@@ -955,9 +931,9 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.14.0"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0"
checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1"
[[package]]
name = "open"
@@ -1074,9 +1050,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.43"
version = "1.0.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b"
dependencies = [
"unicode-ident",
]
@@ -1200,9 +1176,9 @@ dependencies = [
[[package]]
name = "rgb"
version = "0.8.33"
version = "0.8.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3b221de559e4a29df3b957eec92bc0de6bc8eaf6ca9cfed43e5e1d67ff65a34"
checksum = "3603b7d71ca82644f79b5a06d1220e9a58ede60bd32255f698cb1af8838b8db3"
dependencies = [
"bytemuck",
]
@@ -1242,18 +1218,18 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "serde"
version = "1.0.144"
version = "1.0.145"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860"
checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.144"
version = "1.0.145"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00"
checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c"
dependencies = [
"proc-macro2",
"quote",
@@ -1303,9 +1279,9 @@ dependencies = [
[[package]]
name = "smallvec"
version = "1.9.0"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
[[package]]
name = "spin"
@@ -1336,9 +1312,9 @@ checksum = "e72d8b19ab05827afefcca66bf47040c1e66a0901eb814784c77d4ec118bd309"
[[package]]
name = "syn"
version = "1.0.99"
version = "1.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13"
checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2"
dependencies = [
"proc-macro2",
"quote",
@@ -1370,9 +1346,9 @@ dependencies = [
[[package]]
name = "termimad"
version = "0.20.2"
version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8a16d7de8d4c97a4149cc3b9d3681c5dba36011c303745bb1af19636e89ba39"
checksum = "3977554523f42b473e5211e5fbb39e78e21e793ff6ffd6428ae3bd02dbb7e09d"
dependencies = [
"coolor",
"crossbeam",
@@ -1390,26 +1366,20 @@ dependencies = [
"image",
]
[[package]]
name = "textwrap"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
[[package]]
name = "thiserror"
version = "1.0.35"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c53f98874615aea268107765aa1ed8f6116782501d18e53d08b471733bea6c85"
checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.35"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8b463991b4eab2d801e724172285ec4195c650e8ec79b149e6c2a8e6dd3f783"
checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
dependencies = [
"proc-macro2",
"quote",
@@ -1470,25 +1440,19 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
[[package]]
name = "unicode-ident"
version = "1.0.3"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf"
checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd"
[[package]]
name = "unicode-normalization"
version = "0.1.21"
version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6"
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-segmentation"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a"
[[package]]
name = "unicode-width"
version = "0.1.10"
+9 -4
View File
@@ -21,15 +21,15 @@ exclude = ["/data"]
[dependencies]
num-traits = "0.2.15"
once_cell = "1.14.0"
thiserror = "1.0.35"
once_cell = "1.15.0"
thiserror = "1.0.37"
[dev-dependencies]
glassbench = "0.3.3"
image = "0.24.3"
image = "0.24.4"
resize = "0.7.4"
rgb = "0.8.33"
rgb = "0.8.34"
png = "0.17.6"
nix = { version = "0.25.0", default-features = false, features = ["sched"] }
testing = {path= "testing" }
@@ -85,6 +85,11 @@ name = "bench_compare_la16"
harness = false
[[bench]]
name = "bench_color_mapper"
harness = false
[profile.dev.package.'*']
opt-level = 3
+31 -20
View File
@@ -6,12 +6,6 @@
Rust library for fast image resizing with using of SIMD instructions.
_Note: This library does not support converting image color spaces.
If it is important for you to resize images with a non-linear color space
(e.g. sRGB) correctly, then you need to convert it to a linear color space
before resizing. [Read more](https://legacy.imagemagick.org/Usage/resize/#resize_colorspace)
about resizing with respect to color space._
[CHANGELOG](https://github.com/Cykooz/fast_image_resize/blob/main/CHANGELOG.md)
Supported pixel formats and available optimisations:
@@ -29,6 +23,23 @@ Supported pixel formats and available optimisations:
| I32 | One `i32` component per pixel | + | - | - |
| F32 | One `f32` component per pixel | + | - | - |
## Colorspace
Resizer from this crate does not convert image into linear color space
during resize process. If it is important for you to resize images with a
non-linear color space (e.g. sRGB) correctly, then you need to convert
it to a linear color space before resizing and convert back a color space of
result image. [Read more](https://legacy.imagemagick.org/Usage/resize/#resize_colorspace)
about resizing with respect to color space.
This crate provides the
[PixelComponentMapper](https://docs.rs/fast_image_resize/target/doc/fast_image_resize/color/struct.PixelComponentMapper.html)
structure that allows you to create color space converters for images
whose pixels based on `u8` and `u16` components.
In addition, the crate contains lazy-static instances of the `PixelComponentMapper`
structure: `SRGB_TO_RGB` and `GAMMA22_TO_LINEAR`.
## Some benchmarks
[All benchmarks.](https://github.com/Cykooz/fast_image_resize/blob/main/benchmarks.md)
@@ -49,11 +60,11 @@ Pipeline:
| | Nearest | Bilinear | CatmullRom | Lanczos3 |
|------------|:-------:|:--------:|:----------:|:--------:|
| image | 19.01 | 84.06 | 148.84 | 205.25 |
| resize | - | 52.21 | 104.32 | 154.11 |
| fir rust | 0.28 | 41.75 | 76.85 | 113.11 |
| fir sse4.1 | 0.28 | 28.16 | 43.00 | 59.62 |
| fir avx2 | 0.28 | 7.41 | 9.61 | 13.84 |
| image | 19.37 | 82.24 | 141.62 | 200.90 |
| resize | - | 51.49 | 102.74 | 153.21 |
| fir rust | 0.28 | 44.07 | 81.14 | 119.43 |
| fir sse4.1 | 0.28 | 28.22 | 43.29 | 57.77 |
| fir avx2 | 0.28 | 7.47 | 9.65 | 13.86 |
### Resize RGBA8 image (U8x4) 4928x3279 => 852x567
@@ -68,10 +79,10 @@ Pipeline:
| | Nearest | Bilinear | CatmullRom | Lanczos3 |
|------------|:-------:|:--------:|:----------:|:--------:|
| resize | - | 61.94 | 122.19 | 182.60 |
| fir rust | 0.19 | 37.33 | 53.29 | 76.49 |
| fir sse4.1 | 0.19 | 13.14 | 17.25 | 22.59 |
| fir avx2 | 0.19 | 9.59 | 12.09 | 16.18 |
| resize | - | 62.30 | 122.50 | 182.64 |
| fir rust | 0.19 | 37.27 | 53.06 | 75.83 |
| fir sse4.1 | 0.19 | 13.20 | 17.29 | 22.74 |
| fir avx2 | 0.19 | 9.58 | 12.09 | 16.24 |
### Resize L8 image (U8) 4928x3279 => 852x567
@@ -85,11 +96,11 @@ Pipeline:
| | Nearest | Bilinear | CatmullRom | Lanczos3 |
|------------|:-------:|:--------:|:----------:|:--------:|
| image | 15.60 | 45.30 | 72.95 | 102.13 |
| resize | - | 17.29 | 35.45 | 61.14 |
| fir rust | 0.15 | 13.91 | 15.37 | 22.86 |
| fir sse4.1 | 0.15 | 12.16 | 12.16 | 18.19 |
| fir avx2 | 0.15 | 6.33 | 4.66 | 7.69 |
| image | 15.80 | 46.71 | 74.50 | 102.36 |
| resize | - | 17.33 | 35.75 | 61.46 |
| fir rust | 0.16 | 14.63 | 16.86 | 24.73 |
| fir sse4.1 | 0.16 | 12.32 | 12.37 | 18.32 |
| fir avx2 | 0.16 | 6.29 | 4.69 | 7.94 |
## Examples
+28
View File
@@ -0,0 +1,28 @@
use glassbench::*;
use std::ops::Deref;
use fast_image_resize::color::mappers::SRGB_TO_RGB;
use fast_image_resize::pixels::U8x3;
use fast_image_resize::Image;
use testing::PixelTestingExt;
mod utils;
pub fn bench_color_mapper(bench: &mut Bench) {
let src_image = U8x3::load_big_src_image();
let mut dst_image = Image::new(
src_image.width(),
src_image.height(),
src_image.pixel_type(),
);
let src_view = src_image.view();
let mut dst_view = dst_image.view_mut();
let mapper = SRGB_TO_RGB.deref();
bench.task("SRGB U8x3 => RGB U8x3", |task| {
task.iter(|| {
mapper.forward_map(&src_view, &mut dst_view).unwrap();
})
});
}
bench_main!("Bench color mappers", bench_color_mapper,);
+1 -1
View File
@@ -9,7 +9,7 @@ use rgb::FromSlice;
use fast_image_resize::pixels::U8;
use fast_image_resize::Image;
use fast_image_resize::{CpuExtensions, FilterType, ResizeAlg, Resizer};
use testing::PixelExt;
use testing::PixelTestingExt;
mod utils;
+1 -1
View File
@@ -9,7 +9,7 @@ use rgb::FromSlice;
use fast_image_resize::pixels::U16;
use fast_image_resize::Image;
use fast_image_resize::{CpuExtensions, FilterType, ResizeAlg, Resizer};
use testing::PixelExt;
use testing::PixelTestingExt;
mod utils;
+1 -1
View File
@@ -4,7 +4,7 @@ use glassbench::*;
use fast_image_resize::pixels::U8x2;
use fast_image_resize::{CpuExtensions, FilterType, Image, MulDiv, PixelType, ResizeAlg, Resizer};
use testing::PixelExt;
use testing::PixelTestingExt;
mod utils;
+1 -1
View File
@@ -4,7 +4,7 @@ use glassbench::*;
use fast_image_resize::pixels::U16x2;
use fast_image_resize::{CpuExtensions, FilterType, Image, MulDiv, PixelType, ResizeAlg, Resizer};
use testing::PixelExt;
use testing::PixelTestingExt;
mod utils;
+1 -1
View File
@@ -8,7 +8,7 @@ use rgb::{FromSlice, RGB};
use fast_image_resize::pixels::U8x3;
use fast_image_resize::Image;
use fast_image_resize::{CpuExtensions, FilterType, ResizeAlg, Resizer};
use testing::PixelExt;
use testing::PixelTestingExt;
mod utils;
+1 -1
View File
@@ -8,7 +8,7 @@ use rgb::{FromSlice, RGB};
use fast_image_resize::pixels::U16x3;
use fast_image_resize::Image;
use fast_image_resize::{CpuExtensions, FilterType, ResizeAlg, Resizer};
use testing::PixelExt;
use testing::PixelTestingExt;
mod utils;
+1 -1
View File
@@ -7,7 +7,7 @@ use rgb::FromSlice;
use fast_image_resize::pixels::U8x4;
use fast_image_resize::{CpuExtensions, FilterType, Image, MulDiv, ResizeAlg, Resizer};
use testing::PixelExt;
use testing::PixelTestingExt;
mod utils;
+1 -1
View File
@@ -6,7 +6,7 @@ use std::num::NonZeroU32;
use fast_image_resize::pixels::U16x4;
use fast_image_resize::{CpuExtensions, FilterType, Image, MulDiv, ResizeAlg, Resizer};
use testing::PixelExt;
use testing::PixelTestingExt;
mod utils;
+1 -1
View File
@@ -5,7 +5,7 @@ use glassbench::*;
use fast_image_resize::pixels::*;
use fast_image_resize::Image;
use fast_image_resize::{CpuExtensions, FilterType, PixelType, ResizeAlg, Resizer};
use testing::{cpu_ext_into_str, PixelExt};
use testing::{cpu_ext_into_str, PixelTestingExt};
mod utils;
+38 -38
View File
@@ -5,14 +5,14 @@ Environment:
- CPU: AMD Ryzen 9 5950X
- RAM: DDR4 3800 MHz
- Ubuntu 22.04 (linux 5.15.0)
- Rust 1.62.1
- fast_image_resize = "1.0.0"
- Rust 1.64
- fast_image_resize = "2.0.0"
- glassbench = "0.3.3"
Other Rust libraries used to compare of resizing speed:
- image = "0.24.3" (<https://crates.io/crates/image>)
- resize = "0.7.3" (<https://crates.io/crates/resize>)
- image = "0.24.4" (<https://crates.io/crates/image>)
- resize = "0.7.4" (<https://crates.io/crates/resize>)
Resize algorithms:
@@ -32,11 +32,11 @@ Pipeline:
| | Nearest | Bilinear | CatmullRom | Lanczos3 |
|------------|:-------:|:--------:|:----------:|:--------:|
| image | 19.01 | 84.06 | 148.84 | 205.25 |
| resize | - | 52.21 | 104.32 | 154.11 |
| fir rust | 0.28 | 41.75 | 76.85 | 113.11 |
| fir sse4.1 | 0.28 | 28.16 | 43.00 | 59.62 |
| fir avx2 | 0.28 | 7.41 | 9.61 | 13.84 |
| image | 19.37 | 82.24 | 141.62 | 200.90 |
| resize | - | 51.49 | 102.74 | 153.21 |
| fir rust | 0.28 | 44.07 | 81.14 | 119.43 | ?
| fir sse4.1 | 0.28 | 28.22 | 43.29 | 57.77 |
| fir avx2 | 0.28 | 7.47 | 9.65 | 13.86 |
### Resize RGBA8 image (U8x4) 4928x3279 => 852x567
@@ -51,10 +51,10 @@ Pipeline:
| | Nearest | Bilinear | CatmullRom | Lanczos3 |
|------------|:-------:|:--------:|:----------:|:--------:|
| resize | - | 61.94 | 122.19 | 182.60 |
| fir rust | 0.19 | 37.33 | 53.29 | 76.49 |
| fir sse4.1 | 0.19 | 13.14 | 17.25 | 22.59 |
| fir avx2 | 0.19 | 9.59 | 12.09 | 16.18 |
| resize | - | 62.30 | 122.50 | 182.64 |
| fir rust | 0.19 | 37.27 | 53.06 | 75.83 |
| fir sse4.1 | 0.19 | 13.20 | 17.29 | 22.74 |
| fir avx2 | 0.19 | 9.58 | 12.09 | 16.24 |
### Resize L8 image (U8) 4928x3279 => 852x567
@@ -68,11 +68,11 @@ Pipeline:
| | Nearest | Bilinear | CatmullRom | Lanczos3 |
|------------|:-------:|:--------:|:----------:|:--------:|
| image | 15.60 | 45.30 | 72.95 | 102.13 |
| resize | - | 17.29 | 35.45 | 61.14 |
| fir rust | 0.15 | 13.91 | 15.37 | 22.86 |
| fir sse4.1 | 0.15 | 12.16 | 12.16 | 18.19 |
| fir avx2 | 0.15 | 6.33 | 4.66 | 7.69 |
| image | 15.80 | 46.71 | 74.50 | 102.36 |
| resize | - | 17.33 | 35.75 | 61.46 |
| fir rust | 0.16 | 14.63 | 16.86 | 24.73 | ?
| fir sse4.1 | 0.16 | 12.32 | 12.37 | 18.32 |
| fir avx2 | 0.16 | 6.29 | 4.69 | 7.94 |
### Resize LA8 image (U8x2) 4928x3279 => 852x567
@@ -89,9 +89,9 @@ Pipeline:
| | Nearest | Bilinear | CatmullRom | Lanczos3 |
|------------|:-------:|:--------:|:----------:|:--------:|
| fir rust | 0.17 | 25.48 | 31.83 | 43.72 |
| fir sse4.1 | 0.17 | 12.81 | 14.69 | 18.12 |
| fir avx2 | 0.17 | 11.27 | 12.45 | 15.48 |
| fir rust | 0.17 | 25.97 | 31.36 | 43.22 |
| fir sse4.1 | 0.17 | 12.77 | 14.64 | 18.07 |
| fir avx2 | 0.17 | 11.26 | 12.45 | 15.45 |
### Resize RGB16 image (U16x3) 4928x3279 => 852x567
@@ -105,11 +105,11 @@ Pipeline:
| | Nearest | Bilinear | CatmullRom | Lanczos3 |
|------------|:-------:|:--------:|:----------:|:--------:|
| image | 18.28 | 75.10 | 137.04 | 189.89 |
| resize | - | 54.71 | 106.93 | 158.29 |
| fir rust | 0.33 | 43.65 | 79.56 | 117.31 |
| fir sse4.1 | 0.33 | 24.34 | 39.55 | 55.89 |
| fir avx2 | 0.33 | 20.67 | 30.81 | 36.98 |
| image | 19.08 | 75.99 | 138.66 | 191.07 |
| resize | - | 54.82 | 106.80 | 158.63 |
| fir rust | 0.33 | 42.57 | 71.01 | 100.55 |
| fir sse4.1 | 0.33 | 24.41 | 39.39 | 55.82 |
| fir avx2 | 0.33 | 20.59 | 30.53 | 36.28 |
### Resize RGBA16 image (U16x4) 4928x3279 => 852x567
@@ -124,10 +124,10 @@ Pipeline:
| | Nearest | Bilinear | CatmullRom | Lanczos3 |
|------------|:-------:|:--------:|:----------:|:--------:|
| resize | - | 63.93 | 127.61 | 191.17 |
| fir rust | 0.40 | 89.83 | 125.96 | 167.05 |
| fir sse4.1 | 0.40 | 42.24 | 63.53 | 85.53 |
| fir avx2 | 0.40 | 23.53 | 34.14 | 45.43 |
| resize | - | 63.87 | 127.55 | 191.89 |
| fir rust | 0.36 | 85.57 | 124.24 | 163.89 |
| fir sse4.1 | 0.36 | 42.25 | 63.57 | 85.65 |
| fir avx2 | 0.36 | 23.51 | 34.20 | 45.55 |
### Resize L16 image (U16) 4928x3279 => 852x567
@@ -141,11 +141,11 @@ Pipeline:
| | Nearest | Bilinear | CatmullRom | Lanczos3 |
|------------|:-------:|:--------:|:----------:|:--------:|
| image | 15.53 | 45.82 | 73.87 | 103.21 |
| resize | - | 15.44 | 31.92 | 57.15 |
| fir rust | 0.18 | 18.86 | 27.52 | 38.34 |
| fir sse4.1 | 0.18 | 7.93 | 13.28 | 19.24 |
| fir avx2 | 0.18 | 7.16 | 9.50 | 14.54 |
| image | 15.81 | 48.15 | 75.73 | 104.58 |
| resize | - | 15.46 | 32.02 | 57.12 |
| fir rust | 0.17 | 18.98 | 29.12 | 41.17 | ?
| fir sse4.1 | 0.17 | 7.79 | 13.24 | 19.14 |
| fir avx2 | 0.17 | 7.09 | 9.49 | 14.83 |
### Resize LA16 (luma with alpha channel) image (U16x2) 4928x3279 => 852x567
@@ -162,6 +162,6 @@ Pipeline:
| | Nearest | Bilinear | CatmullRom | Lanczos3 |
|------------|:-------:|:--------:|:----------:|:--------:|
| fir rust | 0.19 | 33.54 | 52.84 | 71.97 |
| fir sse4.1 | 0.19 | 21.87 | 34.08 | 46.61 |
| fir avx2 | 0.19 | 15.19 | 21.93 | 29.07 |
| fir rust | 0.19 | 33.72 | 52.63 | 71.65 |
| fir sse4.1 | 0.19 | 21.80 | 33.99 | 46.62 |
| fir avx2 | 0.19 | 15.10 | 21.85 | 29.03 |
+5 -5
View File
@@ -7,9 +7,9 @@ edition = "2021"
[dependencies]
fast_image_resize = {path=".."}
image = "0.24.2"
clap = { version = "3.2.14", features = ["derive"] }
image = "0.24.4"
clap = { version = "4.0.9", features = ["derive"] }
log = "0.4.17"
env_logger = "0.9.0"
anyhow = "1.0.58"
clap-verbosity-flag = "1.0.1"
env_logger = "0.9.1"
anyhow = "1.0.65"
clap-verbosity-flag = "2.0.0"
+32 -12
View File
@@ -24,13 +24,13 @@ struct Cli {
#[clap(value_parser)]
destination_path: Option<PathBuf>,
/// Width of result image
/// Width of result image, in pixels or percentage of the source image's width
#[clap(short, long, value_parser)]
width: Option<NonZeroU32>,
width: Option<structs::Size>,
/// Height of result image
/// Height of result image in pixels or percentage of the source image's width height
#[clap(short, long, value_parser)]
height: Option<NonZeroU32>,
height: Option<structs::Size>,
/// Overwrite destination file
#[clap(short, long, action)]
@@ -226,15 +226,24 @@ fn create_destination_image(cli: &Cli, src_image: &fr::Image) -> fr::Image<'stat
let (dst_width, dst_height) = match (cli.width, cli.height) {
(None, None) => (src_image.width(), src_image.height()),
(Some(width), None) => (
width,
get_non_zero_u32((width.get() as f32 / aspect_ratio).round() as u32),
(Some(width), None) => {
let width = width.calculate_size(src_image.width());
(
width,
get_non_zero_u32((width.get() as f32 / aspect_ratio).round() as u32),
)
}
(None, Some(height)) => {
let height = height.calculate_size(src_image.height());
(
get_non_zero_u32((height.get() as f32 * aspect_ratio).round() as u32),
height,
)
}
(Some(width), Some(height)) => (
width.calculate_size(src_image.width()),
height.calculate_size(src_image.height()),
),
(None, Some(height)) => (
get_non_zero_u32((height.get() as f32 * aspect_ratio).round() as u32),
height,
),
(Some(width), Some(height)) => (width, height),
};
fr::Image::new(dst_width, dst_height, src_image.pixel_type())
@@ -317,3 +326,14 @@ fn save_result(
.with_context(|| "Failed to save the result image")?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn verify_cli() {
use clap::CommandFactory;
Cli::command().debug_assert()
}
}
+32
View File
@@ -1,4 +1,36 @@
use crate::get_non_zero_u32;
use fast_image_resize as fr;
use std::num::{NonZeroU16, NonZeroU32, ParseIntError};
use std::str::FromStr;
#[derive(Copy, Clone, Debug)]
pub enum Size {
Pixels(NonZeroU32),
Percent(NonZeroU16),
}
impl Size {
pub fn calculate_size(&self, src_size: NonZeroU32) -> NonZeroU32 {
match *self {
Self::Pixels(size) => size,
Self::Percent(percent) => get_non_zero_u32(
(src_size.get() as f32 * percent.get() as f32 / 100.).round() as u32,
),
}
}
}
impl FromStr for Size {
type Err = ParseIntError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if let Some(percent_str) = s.strip_suffix('%') {
NonZeroU16::from_str(percent_str).map(Self::Percent)
} else {
NonZeroU32::from_str(s).map(Self::Pixels)
}
}
}
#[derive(Copy, Clone, Debug, clap::ValueEnum)]
pub enum Algorithm {
+2 -2
View File
@@ -1,6 +1,6 @@
pub use errors::*;
use crate::pixels::Pixel;
use crate::pixels::PixelExt;
use crate::CpuExtensions;
use crate::{ImageView, ImageViewMut};
@@ -13,7 +13,7 @@ mod u8x4;
pub(crate) trait AlphaMulDiv
where
Self: Pixel,
Self: PixelExt,
{
/// Multiplies RGB-channels of source image by alpha-channel and store
/// result into destination image.
+2 -2
View File
@@ -112,13 +112,13 @@ pub(crate) unsafe fn divide_alpha_row(src_row: &[U16x2], dst_row: &mut [U16x2])
if !src_remainder.is_empty() {
let dst_reminder = dst_chunks.into_remainder();
let mut src_pixels = [U16x2([0, 0]); 8];
let mut src_pixels = [U16x2::new([0, 0]); 8];
src_pixels
.iter_mut()
.zip(src_remainder)
.for_each(|(d, s)| *d = *s);
let mut dst_pixels = [U16x2([0, 0]); 8];
let mut dst_pixels = [U16x2::new([0, 0]); 8];
divide_alpha_eight_pixels(src_pixels.as_ptr(), dst_pixels.as_mut_ptr());
dst_pixels
+2 -2
View File
@@ -108,13 +108,13 @@ pub(crate) unsafe fn divide_alpha_row(src_row: &[U16x2], dst_row: &mut [U16x2])
if !src_remainder.is_empty() {
let dst_reminder = dst_chunks.into_remainder();
let mut src_pixels = [U16x2([0, 0]); 4];
let mut src_pixels = [U16x2::new([0, 0]); 4];
src_pixels
.iter_mut()
.zip(src_remainder)
.for_each(|(d, s)| *d = *s);
let mut dst_pixels = [U16x2([0, 0]); 4];
let mut dst_pixels = [U16x2::new([0, 0]); 4];
divide_alpha_four_pixels(src_pixels.as_ptr(), dst_pixels.as_mut_ptr());
dst_pixels
+2 -2
View File
@@ -111,13 +111,13 @@ pub(crate) unsafe fn divide_alpha_row(src_row: &[U16x4], dst_row: &mut [U16x4])
if !src_remainder.is_empty() {
let dst_reminder = dst_chunks.into_remainder();
let mut src_pixels = [U16x4([0, 0, 0, 0]); 4];
let mut src_pixels = [U16x4::new([0, 0, 0, 0]); 4];
src_pixels
.iter_mut()
.zip(src_remainder)
.for_each(|(d, s)| *d = *s);
let mut dst_pixels = [U16x4([0, 0, 0, 0]); 4];
let mut dst_pixels = [U16x4::new([0, 0, 0, 0]); 4];
divide_alpha_four_pixels(src_pixels.as_ptr(), dst_pixels.as_mut_ptr());
dst_pixels
+2 -2
View File
@@ -107,8 +107,8 @@ pub(crate) unsafe fn divide_alpha_row(src_row: &[U16x4], dst_row: &mut [U16x4])
}
if let Some(src) = src_remainder.first() {
let src_pixels = [*src, U16x4([0, 0, 0, 0])];
let mut dst_pixels = [U16x4([0, 0, 0, 0]); 2];
let src_pixels = [*src, U16x4::new([0, 0, 0, 0])];
let mut dst_pixels = [U16x4::new([0, 0, 0, 0]); 2];
divide_alpha_two_pixels(src_pixels.as_ptr(), dst_pixels.as_mut_ptr());
let dst_reminder = dst_chunks.into_remainder();
+2 -2
View File
@@ -105,13 +105,13 @@ pub(crate) unsafe fn divide_alpha_row(src_row: &[U8x2], dst_row: &mut [U8x2]) {
if !src_remainder.is_empty() {
let dst_reminder = dst_chunks.into_remainder();
let mut src_pixels = [U8x2(0); 8];
let mut src_pixels = [U8x2::new(0); 8];
src_pixels
.iter_mut()
.zip(src_remainder)
.for_each(|(d, s)| *d = *s);
let mut dst_pixels = [U8x2(0); 8];
let mut dst_pixels = [U8x2::new(0); 8];
divide_alpha_eight_pixels(src_pixels.as_ptr(), dst_pixels.as_mut_ptr());
dst_pixels
+2 -2
View File
@@ -101,13 +101,13 @@ pub(crate) unsafe fn divide_alpha_row(src_row: &[U8x4], dst_row: &mut [U8x4]) {
if !src_remainder.is_empty() {
let dst_reminder = dst_chunks.into_remainder();
let mut src_pixels = [U8x4(0); 4];
let mut src_pixels = [U8x4::new(0); 4];
src_pixels
.iter_mut()
.zip(src_remainder)
.for_each(|(d, s)| *d = *s);
let mut dst_pixels = [U8x4(0); 4];
let mut dst_pixels = [U8x4::new(0); 4];
divide_alpha_four_pixels(src_pixels.as_ptr(), dst_pixels.as_mut_ptr());
dst_pixels
+94 -16
View File
@@ -9,7 +9,7 @@
use num_traits::bounds::UpperBounded;
use num_traits::Zero;
use crate::pixels::{GetCount, IntoPixelComponent, Pixel, PixelComponent, Values};
use crate::pixels::{GetCount, IntoPixelComponent, PixelComponent, PixelExt, Values};
use crate::{DynamicImageView, DynamicImageViewMut, MappingError};
use crate::{ImageView, ImageViewMut};
@@ -31,13 +31,13 @@ impl FromF32 for u16 {
}
}
struct MappingTable<Out: PixelComponent, const N: usize>([Out; N]);
struct MappingTable<Out: PixelComponent, const SIZE: usize>([Out; SIZE]);
impl<Out, const SIZE: usize> MappingTable<Out, SIZE>
where
Out: PixelComponent + Zero + UpperBounded + FromF32 + Into<f32>,
{
pub fn new<F>(map_func: &F) -> MappingTable<Out, SIZE>
pub fn new<F>(map_func: &F) -> Self
where
F: Fn(f32) -> f32,
{
@@ -58,6 +58,16 @@ where
}
}
fn map_inplace(&self, buffer: &mut [Out])
where
Out: Into<usize>,
{
for c in buffer.iter_mut() {
let i: usize = (*c).into();
*c = self.0[i];
}
}
fn map_with_gaps<In>(&self, src_buffer: &[In], dst_buffer: &mut [Out], gap_step: usize)
where
In: IntoPixelComponent<Out> + Into<usize>,
@@ -71,20 +81,26 @@ where
}
}
pub fn map_image<S, D, CC, In>(&self, src_image: &ImageView<S>, dst_image: &mut ImageViewMut<D>)
fn map_with_gaps_inplace(&self, buffer: &mut [Out], gap_step: usize)
where
In: IntoPixelComponent<Out> + Into<usize>,
Out: Into<usize>,
{
for (i, c) in buffer.iter_mut().enumerate() {
if (i + 1) % gap_step != 0 {
let i: usize = (*c).into();
*c = self.0[i];
}
}
}
pub fn map_image<S, D, In, CC>(&self, src_image: &ImageView<S>, dst_image: &mut ImageViewMut<D>)
where
In: PixelComponent<CountOfComponentValues = Values<SIZE>>
+ IntoPixelComponent<Out>
+ Into<usize>,
CC: GetCount,
S: Pixel<
Component = In,
CountOfComponents = CC, // Count of source pixel's components
CountOfComponentValues = Values<SIZE>, // Total count of values of one source pixel's component
>,
S::Component: Into<usize>,
D: Pixel<
Component = Out,
CountOfComponents = CC, // Count of destination pixel's components
>,
S: PixelExt<Component = In, CountOfComponents = CC>,
D: PixelExt<Component = Out, CountOfComponents = CC>,
{
for (s_row, d_row) in src_image.iter_rows(0).zip(dst_image.iter_rows_mut()) {
let s_comp = S::components(s_row);
@@ -96,6 +112,22 @@ where
}
}
}
pub fn map_image_inplace<S, CC>(&self, image: &mut ImageViewMut<S>)
where
CC: GetCount,
S: PixelExt<Component = Out, CountOfComponents = CC>,
Out: Into<usize>,
{
for row in image.iter_rows_mut() {
let comp = S::components_mut(row);
match CC::count() {
2 => self.map_with_gaps_inplace(comp, 2), // Don't map alpha channel
4 => self.map_with_gaps_inplace(comp, 4), // Don't map alpha channel
_ => self.map_inplace(comp),
}
}
}
}
struct MappingTablesGroup {
@@ -109,6 +141,10 @@ struct MappingTablesGroup {
///
/// This structure holds tables for mapping values of pixel's
/// components in forward and backward directions.
///
/// Alpha channel from such pixel types as `U8x2`, `U8x4`, `U16x2` and `U16x4`
/// not mapped with tables. This component transformed into destination
/// component type with help of [IntoPixelComponent] trait.
pub struct PixelComponentMapper {
forward_mapping_tables: MappingTablesGroup,
backward_mapping_tables: MappingTablesGroup,
@@ -160,7 +196,6 @@ impl PixelComponentMapper {
}
}
#[inline]
fn map(
tables: &MappingTablesGroup,
src_image: &DynamicImageView,
@@ -202,6 +237,38 @@ impl PixelComponentMapper {
Ok(())
}
fn map_inplace(
tables: &MappingTablesGroup,
image: &mut DynamicImageViewMut,
) -> Result<(), MappingError> {
use DynamicImageViewMut as DIMut;
macro_rules! match_img {
(
$tables: ident, $image: ident,
$(($p8_mut: path, $p16_mut: path),)*
) => {
match $image {
$(
$p8_mut(img) => $tables.u8_u8.map_image_inplace(img),
$p16_mut(img) => $tables.u16_u16.map_image_inplace(img),
)*
_ => return Err(MappingError::UnsupportedCombinationOfImageTypes),
}
};
}
match_img!(
tables,
image,
(DIMut::U8, DIMut::U16),
(DIMut::U8x2, DIMut::U16x2),
(DIMut::U8x3, DIMut::U16x3),
(DIMut::U8x4, DIMut::U16x4),
);
Ok(())
}
/// Mapping in the forward direction of pixel's components of source image
/// into corresponding components of destination image.
pub fn forward_map(
@@ -212,6 +279,10 @@ impl PixelComponentMapper {
Self::map(&self.forward_mapping_tables, src_image, dst_image)
}
pub fn forward_map_inplace(&self, image: &mut DynamicImageViewMut) -> Result<(), MappingError> {
Self::map_inplace(&self.forward_mapping_tables, image)
}
/// Mapping in the backward direction of pixel's components of source image
/// into corresponding components of destination image.
pub fn backward_map(
@@ -221,4 +292,11 @@ impl PixelComponentMapper {
) -> Result<(), MappingError> {
Self::map(&self.backward_mapping_tables, src_image, dst_image)
}
pub fn backward_map_inplace(
&self,
image: &mut DynamicImageViewMut,
) -> Result<(), MappingError> {
Self::map_inplace(&self.backward_mapping_tables, image)
}
}
+2 -2
View File
@@ -2,7 +2,7 @@ use std::num::NonZeroU32;
pub use filters::{get_filter_func, FilterType};
use crate::pixels::Pixel;
use crate::pixels::PixelExt;
use crate::CpuExtensions;
use crate::{ImageView, ImageViewMut};
@@ -26,7 +26,7 @@ mod vertical_u8;
pub(crate) trait Convolution
where
Self: Pixel,
Self: PixelExt,
{
fn horiz_convolution(
src_image: &ImageView<Self>,
+3 -3
View File
@@ -1,7 +1,7 @@
use std::arch::x86_64::*;
use crate::convolution::{optimisations, Coefficients};
use crate::pixels::Pixel;
use crate::pixels::PixelExt;
use crate::simd_utils;
use crate::{ImageView, ImageViewMut};
@@ -10,7 +10,7 @@ pub(crate) fn vert_convolution<T>(
dst_image: &mut ImageViewMut<T>,
coeffs: Coefficients,
) where
T: Pixel<Component = u16>,
T: PixelExt<Component = u16>,
{
let normalizer = optimisations::Normalizer32::new(coeffs);
let coefficients_chunks = normalizer.normalized_chunks();
@@ -30,7 +30,7 @@ pub(crate) unsafe fn vert_convolution_into_one_row_u16<T>(
coeffs_chunk: optimisations::CoefficientsI32Chunk,
normalizer: &optimisations::Normalizer32,
) where
T: Pixel<Component = u16>,
T: PixelExt<Component = u16>,
{
let mut xx: usize = 0;
let src_width = src_img.width().get() as usize * T::count_of_components();
+2 -2
View File
@@ -1,5 +1,5 @@
use crate::convolution::Coefficients;
use crate::pixels::Pixel;
use crate::pixels::PixelExt;
use crate::CpuExtensions;
use crate::{ImageView, ImageViewMut};
@@ -9,7 +9,7 @@ pub(crate) mod native;
#[cfg(target_arch = "x86_64")]
pub(crate) mod sse4;
pub(crate) fn vert_convolution_u16<T: Pixel<Component = u16>>(
pub(crate) fn vert_convolution_u16<T: PixelExt<Component = u16>>(
src_image: &ImageView<T>,
dst_image: &mut ImageViewMut<T>,
coeffs: Coefficients,
+3 -3
View File
@@ -1,9 +1,9 @@
use crate::convolution::{optimisations, Coefficients};
use crate::pixels::Pixel;
use crate::pixels::PixelExt;
use crate::{ImageView, ImageViewMut};
#[inline(always)]
pub(crate) fn vert_convolution<T: Pixel<Component = u16>>(
pub(crate) fn vert_convolution<T: PixelExt<Component = u16>>(
src_image: &ImageView<T>,
dst_image: &mut ImageViewMut<T>,
coeffs: Coefficients,
@@ -37,7 +37,7 @@ pub(crate) fn vert_convolution<T: Pixel<Component = u16>>(
}
#[inline(always)]
pub(crate) fn convolution_by_u16<T: Pixel<Component = u16>>(
pub(crate) fn convolution_by_u16<T: PixelExt<Component = u16>>(
src_image: &ImageView<T>,
normalizer: &optimisations::Normalizer32,
initial: i64,
+3 -3
View File
@@ -3,11 +3,11 @@ use std::arch::x86_64::*;
use crate::convolution::optimisations::CoefficientsI32Chunk;
use crate::convolution::vertical_u16::native::convolution_by_u16;
use crate::convolution::{optimisations, Coefficients};
use crate::pixels::Pixel;
use crate::pixels::PixelExt;
use crate::simd_utils;
use crate::{ImageView, ImageViewMut};
pub(crate) fn vert_convolution<T: Pixel<Component = u16>>(
pub(crate) fn vert_convolution<T: PixelExt<Component = u16>>(
src_image: &ImageView<T>,
dst_image: &mut ImageViewMut<T>,
coeffs: Coefficients,
@@ -24,7 +24,7 @@ pub(crate) fn vert_convolution<T: Pixel<Component = u16>>(
}
#[target_feature(enable = "sse4.1")]
unsafe fn vert_convolution_into_one_row_u16<T: Pixel<Component = u16>>(
unsafe fn vert_convolution_into_one_row_u16<T: PixelExt<Component = u16>>(
src_img: &ImageView<T>,
dst_row: &mut [T],
coeffs_chunk: CoefficientsI32Chunk,
+3 -3
View File
@@ -1,7 +1,7 @@
use std::arch::x86_64::*;
use crate::convolution::{optimisations, Coefficients};
use crate::pixels::Pixel;
use crate::pixels::PixelExt;
use crate::simd_utils;
use crate::{ImageView, ImageViewMut};
@@ -11,7 +11,7 @@ pub(crate) fn vert_convolution<T>(
dst_image: &mut ImageViewMut<T>,
coeffs: Coefficients,
) where
T: Pixel<Component = u8>,
T: PixelExt<Component = u8>,
{
let normalizer = optimisations::Normalizer16::new(coeffs);
let coefficients_chunks = normalizer.normalized_chunks();
@@ -32,7 +32,7 @@ unsafe fn vert_convolution_into_one_row_u8<T>(
coeffs_chunk: optimisations::CoefficientsI16Chunk,
normalizer: &optimisations::Normalizer16,
) where
T: Pixel<Component = u8>,
T: PixelExt<Component = u8>,
{
let src_width = src_img.width().get() as usize * T::count_of_components();
let y_start = coeffs_chunk.start;
+2 -2
View File
@@ -1,5 +1,5 @@
use crate::convolution::Coefficients;
use crate::pixels::Pixel;
use crate::pixels::PixelExt;
use crate::CpuExtensions;
use crate::{ImageView, ImageViewMut};
@@ -9,7 +9,7 @@ pub(crate) mod native;
#[cfg(target_arch = "x86_64")]
pub(crate) mod sse4;
pub(crate) fn vert_convolution_u8<T: Pixel<Component = u8>>(
pub(crate) fn vert_convolution_u8<T: PixelExt<Component = u8>>(
src_image: &ImageView<T>,
dst_image: &mut ImageViewMut<T>,
coeffs: Coefficients,
+3 -3
View File
@@ -1,5 +1,5 @@
use crate::convolution::{optimisations, Coefficients};
use crate::pixels::Pixel;
use crate::pixels::PixelExt;
use crate::{ImageView, ImageViewMut};
#[inline(always)]
@@ -8,7 +8,7 @@ pub(crate) fn vert_convolution<T>(
dst_image: &mut ImageViewMut<T>,
coeffs: Coefficients,
) where
T: Pixel<Component = u8>,
T: PixelExt<Component = u8>,
{
// Check safety conditions
debug_assert_eq!(src_image.width(), dst_image.width());
@@ -85,7 +85,7 @@ fn convolution_by_u8<T>(
ks: &[i16],
) -> usize
where
T: Pixel<Component = u8>,
T: PixelExt<Component = u8>,
{
for dst_component in dst_components {
let mut ss = initial;
+3 -3
View File
@@ -1,12 +1,12 @@
use std::arch::x86_64::*;
use crate::convolution::{optimisations, Coefficients};
use crate::pixels::Pixel;
use crate::pixels::PixelExt;
use crate::simd_utils;
use crate::{ImageView, ImageViewMut};
#[inline]
pub(crate) fn vert_convolution<T: Pixel<Component = u8>>(
pub(crate) fn vert_convolution<T: PixelExt<Component = u8>>(
src_image: &ImageView<T>,
dst_image: &mut ImageViewMut<T>,
coeffs: Coefficients,
@@ -23,7 +23,7 @@ pub(crate) fn vert_convolution<T: Pixel<Component = u8>>(
}
#[target_feature(enable = "sse4.1")]
pub(crate) unsafe fn vert_convolution_into_one_row_u8<T: Pixel<Component = u8>>(
pub(crate) unsafe fn vert_convolution_into_one_row_u8<T: PixelExt<Component = u8>>(
src_img: &ImageView<T>,
dst_row: &mut [T],
coeffs_chunk: optimisations::CoefficientsI16Chunk,
+20 -20
View File
@@ -1,15 +1,15 @@
use std::num::NonZeroU32;
use crate::pixels::{Pixel, PixelType};
use crate::pixels::{PixelExt, PixelType};
use crate::{DynamicImageView, DynamicImageViewMut, ImageBufferError, ImageView, ImageViewMut};
#[derive(Debug)]
enum PixelsContainer<'a> {
enum BufferContainer<'a> {
MutU8(&'a mut [u8]),
VecU8(Vec<u8>),
}
impl<'a> PixelsContainer<'a> {
impl<'a> BufferContainer<'a> {
fn as_vec(&self) -> Vec<u8> {
match self {
Self::MutU8(slice) => slice.to_vec(),
@@ -23,7 +23,7 @@ impl<'a> PixelsContainer<'a> {
pub struct Image<'a> {
width: NonZeroU32,
height: NonZeroU32,
pixels: PixelsContainer<'a>,
buffer: BufferContainer<'a>,
pixel_type: PixelType,
}
@@ -31,11 +31,11 @@ impl<'a> Image<'a> {
/// Create empty image with given dimensions and pixel type.
pub fn new(width: NonZeroU32, height: NonZeroU32, pixel_type: PixelType) -> Self {
let pixels_count = (width.get() * height.get()) as usize;
let pixels = PixelsContainer::VecU8(vec![0; pixels_count * pixel_type.size()]);
let buffer = BufferContainer::VecU8(vec![0; pixels_count * pixel_type.size()]);
Self {
width,
height,
pixels,
buffer,
pixel_type,
}
}
@@ -56,7 +56,7 @@ impl<'a> Image<'a> {
Ok(Self {
width,
height,
pixels: PixelsContainer::VecU8(buffer),
buffer: BufferContainer::VecU8(buffer),
pixel_type,
})
}
@@ -77,7 +77,7 @@ impl<'a> Image<'a> {
Ok(Self {
width,
height,
pixels: PixelsContainer::MutU8(buffer),
buffer: BufferContainer::MutU8(buffer),
pixel_type,
})
}
@@ -87,7 +87,7 @@ impl<'a> Image<'a> {
Image {
width: self.width,
height: self.height,
pixels: PixelsContainer::VecU8(self.pixels.as_vec()),
buffer: BufferContainer::VecU8(self.buffer.as_vec()),
pixel_type: self.pixel_type,
}
}
@@ -110,26 +110,26 @@ impl<'a> Image<'a> {
/// Buffer with image pixels.
#[inline(always)]
pub fn buffer(&self) -> &[u8] {
match &self.pixels {
PixelsContainer::MutU8(p) => *p,
PixelsContainer::VecU8(v) => v,
match &self.buffer {
BufferContainer::MutU8(p) => *p,
BufferContainer::VecU8(v) => v,
}
}
/// Mutable buffer with image pixels.
#[inline(always)]
fn buffer_mut(&mut self) -> &mut [u8] {
match &mut self.pixels {
PixelsContainer::MutU8(p) => p,
PixelsContainer::VecU8(ref mut v) => v.as_mut_slice(),
match &mut self.buffer {
BufferContainer::MutU8(p) => p,
BufferContainer::VecU8(ref mut v) => v.as_mut_slice(),
}
}
#[inline(always)]
pub fn into_vec(self) -> Vec<u8> {
match self.pixels {
PixelsContainer::MutU8(p) => p.into(),
PixelsContainer::VecU8(v) => v,
match self.buffer {
BufferContainer::MutU8(p) => p.into(),
BufferContainer::VecU8(v) => v,
}
}
@@ -183,7 +183,7 @@ impl<'a> Image<'a> {
/// Generic image container for internal purposes.
pub(crate) struct InnerImage<'a, P>
where
P: Pixel,
P: PixelExt,
{
width: NonZeroU32,
height: NonZeroU32,
@@ -192,7 +192,7 @@ where
impl<'a, P> InnerImage<'a, P>
where
P: Pixel,
P: PixelExt,
{
pub fn new(width: NonZeroU32, height: NonZeroU32, pixels: &'a mut [P]) -> Self {
Self {
+17 -19
View File
@@ -1,7 +1,8 @@
use std::fmt::Debug;
use std::num::NonZeroU32;
use std::slice;
use crate::pixels::{GetCount, IntoPixelComponent, Pixel, PixelComponent};
use crate::pixels::{GetCount, IntoPixelComponent, PixelComponent, PixelExt};
use crate::{CropBoxError, DifferentDimensionsError, ImageBufferError, ImageRowsError, PixelType};
pub(crate) type RowMut<'a, 'b, T> = &'a mut &'b mut [T];
@@ -27,7 +28,7 @@ pub struct CropBox {
#[derive(Debug, Clone)]
pub struct ImageView<'a, P>
where
P: Pixel,
P: PixelExt,
{
width: NonZeroU32,
height: NonZeroU32,
@@ -37,7 +38,7 @@ where
impl<'a, P> ImageView<'a, P>
where
P: Pixel,
P: PixelExt,
{
pub fn new(
width: NonZeroU32,
@@ -236,7 +237,9 @@ where
#[inline(always)]
pub(crate) fn iter_rows<'s>(&'s self, start_y: u32) -> impl Iterator<Item = &'a [P]> + 's {
self.rows.iter().skip(start_y as usize).copied()
let start_y = start_y as usize;
let rows = self.rows.get(start_y..).unwrap_or(&[]);
rows.iter().copied()
}
#[inline(always)]
@@ -263,12 +266,13 @@ where
#[inline(always)]
pub(crate) fn iter_cropped_rows<'s>(&'s self) -> impl Iterator<Item = &'a [P]> + 's {
let first_row = self.crop_box.top as usize;
let last_row = first_row + self.crop_box.height.get() as usize;
let rows = unsafe { self.rows.get_unchecked(first_row..last_row) };
let first_col = self.crop_box.left as usize;
let last_col = first_col + self.crop_box.width.get() as usize;
self.rows
.iter()
.skip(self.crop_box.top as usize)
.take(self.crop_box.height.get() as usize)
rows.iter()
// Safety guaranteed by method 'set_crop_box'
.map(move |row| unsafe { row.get_unchecked(first_col..last_col) })
}
@@ -278,7 +282,7 @@ where
#[derive(Debug)]
pub struct ImageViewMut<'a, P>
where
P: Pixel,
P: PixelExt,
{
width: NonZeroU32,
height: NonZeroU32,
@@ -287,7 +291,7 @@ where
impl<'a, P> ImageViewMut<'a, P>
where
P: Pixel,
P: PixelExt,
{
pub fn new(
width: NonZeroU32,
@@ -425,7 +429,7 @@ fn align_buffer_to_mut<T>(buffer: &mut [u8]) -> Result<&mut [T], ImageBufferErro
Ok(pixels)
}
pub fn change_type_of_pixel_components<S, D, CC, In, Out>(
pub fn change_type_of_pixel_components<S, D, In, Out, CC>(
src_image: &ImageView<S>,
dst_image: &mut ImageViewMut<D>,
) -> Result<(), DifferentDimensionsError>
@@ -433,14 +437,8 @@ where
Out: PixelComponent,
In: IntoPixelComponent<Out>,
CC: GetCount,
S: Pixel<
Component = In,
CountOfComponents = CC, // Count of source pixel's components
>,
D: Pixel<
Component = Out,
CountOfComponents = CC, // Count of destination pixel's components
>,
S: PixelExt<Component = In, CountOfComponents = CC>,
D: PixelExt<Component = Out, CountOfComponents = CC>,
{
if src_image.width() != dst_image.width() || src_image.height() != dst_image.height() {
return Err(DifferentDimensionsError);
+71 -44
View File
@@ -1,5 +1,6 @@
//! Contains types of pixels.
use std::fmt::Debug;
use std::marker::PhantomData;
use std::mem::size_of;
use std::slice;
@@ -57,49 +58,66 @@ pub trait GetCount {
pub struct Count<const N: usize>;
impl<const N: usize> GetCount for Count<N> {
#[inline(always)]
fn count() -> usize {
N
}
}
pub trait CountOfValues {
pub trait GetCountOfValues {
fn count_of_values() -> usize;
}
/// Generic type to represent the number of available values for a single pixel component.
pub struct Values<const N: usize>;
impl<const N: usize> CountOfValues for Values<N> {
impl<const N: usize> GetCountOfValues for Values<N> {
fn count_of_values() -> usize {
N
}
}
/// Information about one component of pixel.
pub trait PixelComponent
where
Self: Sized + Copy + Debug + 'static,
{
/// Type that provides information about a count of
/// available values of one pixel's component
type CountOfComponentValues: GetCountOfValues;
/// Count of available values of one pixel's component
fn count_of_values() -> usize {
Self::CountOfComponentValues::count_of_values()
}
}
impl PixelComponent for u8 {}
impl PixelComponent for u16 {}
impl PixelComponent for i32 {}
impl PixelComponent for f32 {}
impl PixelComponent for u8 {
type CountOfComponentValues = Values<256>;
}
impl PixelComponent for u16 {
type CountOfComponentValues = Values<65536>;
}
impl PixelComponent for i32 {
type CountOfComponentValues = Values<0>;
}
impl PixelComponent for f32 {
type CountOfComponentValues = Values<0>;
}
pub trait IntoPixelType {
fn pixel_type() -> PixelType;
}
/// Additional information about pixel type.
pub trait Pixel
pub trait PixelExt
where
Self: Copy + Clone + Sized + Debug,
Self: Copy + Clone + Sized + Debug + IntoPixelType,
{
/// Type of pixel components
type Component: PixelComponent;
/// Type that provides information about a count of pixel's components
type CountOfComponents: GetCount;
/// Type that provides information about a count of available values of one
/// pixel's component
type CountOfComponentValues: CountOfValues;
fn pixel_type() -> PixelType;
/// Count of pixel's components
fn count_of_components() -> usize {
@@ -108,14 +126,14 @@ where
/// Count of available values of one pixel's component
fn count_of_component_values() -> usize {
Self::CountOfComponentValues::count_of_values()
Self::Component::count_of_values()
}
/// Size of pixel in bytes
///
/// Example:
/// ```
/// # use fast_image_resize::pixels::{U8x2, U8x3, U8, Pixel};
/// # use fast_image_resize::pixels::{U8x2, U8x3, U8, PixelExt};
/// assert_eq!(U8x3::size(), 3);
/// assert_eq!(U8x2::size(), 2);
/// assert_eq!(U8::size(), 1);
@@ -124,14 +142,14 @@ where
size_of::<Self>()
}
/// Create slice of components of pixels from slice of pixels
/// Create slice of pixel's components from slice of pixels
fn components(buf: &[Self]) -> &[Self::Component] {
let size = buf.len() * Self::count_of_components();
let components_ptr = buf.as_ptr() as *const Self::Component;
unsafe { slice::from_raw_parts(components_ptr, size) }
}
/// Create mutable slice of components of pixels from mutable slice of pixels
/// Create mutable slice of pixel's components from mutable slice of pixels
fn components_mut(buf: &mut [Self]) -> &mut [Self::Component] {
let size = buf.len() * Self::count_of_components();
let components_ptr = buf.as_mut_ptr() as *mut Self::Component;
@@ -139,18 +157,44 @@ where
}
}
/// Generic type of pixel.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(C)]
pub struct Pixel<T, C, const COUNT_OF_COMPONENTS: usize>(
pub T,
PhantomData<[C; COUNT_OF_COMPONENTS]>,
)
where
T: Sized + Copy + Clone + Debug + 'static,
C: PixelComponent;
impl<T, C, const COUNT_OF_COMPONENTS: usize> Pixel<T, C, COUNT_OF_COMPONENTS>
where
T: Sized + Copy + Clone + Debug + 'static,
C: PixelComponent,
{
#[inline(always)]
pub const fn new(v: T) -> Self {
Self(v, PhantomData)
}
}
impl<T, C, const COUNT_OF_COMPONENTS: usize> PixelExt for Pixel<T, C, COUNT_OF_COMPONENTS>
where
Self: IntoPixelType,
T: Sized + Copy + Clone + Debug + 'static,
C: PixelComponent,
{
type Component = C;
type CountOfComponents = Count<COUNT_OF_COMPONENTS>;
}
macro_rules! pixel_struct {
($name:ident, $type:tt, $comp_type:tt, $comp_count:literal, $comp_values:literal, $pixel_type:expr, $doc:expr) => {
($name:ident, $type:tt, $comp_type:tt, $comp_count:literal, $pixel_type:expr, $doc:expr) => {
#[doc = $doc]
#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(C)]
pub struct $name(pub $type);
impl Pixel for $name {
type Component = $comp_type;
type CountOfComponents = Count<$comp_count>;
type CountOfComponentValues = Values<$comp_values>;
pub type $name = Pixel<$type, $comp_type, $comp_count>;
impl IntoPixelType for $name {
fn pixel_type() -> PixelType {
$pixel_type
}
@@ -158,21 +202,12 @@ macro_rules! pixel_struct {
};
}
pixel_struct!(
U8,
u8,
u8,
1,
256,
PixelType::U8,
"One byte per pixel (e.g. L8)"
);
pixel_struct!(U8, u8, u8, 1, PixelType::U8, "One byte per pixel (e.g. L8)");
pixel_struct!(
U8x2,
u16,
u8,
2,
256,
PixelType::U8x2,
"Two bytes per pixel (e.g. LA8)"
);
@@ -181,7 +216,6 @@ pixel_struct!(
[u8; 3],
u8,
3,
256,
PixelType::U8x3,
"Three bytes per pixel (e.g. RGB8)"
);
@@ -190,7 +224,6 @@ pixel_struct!(
u32,
u8,
4,
256,
PixelType::U8x4,
"Four bytes per pixel (RGBA8, RGBx8, CMYK8 and other)"
);
@@ -199,7 +232,6 @@ pixel_struct!(
u16,
u16,
1,
65536,
PixelType::U16,
"One `u16` component per pixel (e.g. L16)"
);
@@ -208,7 +240,6 @@ pixel_struct!(
[u16; 2],
u16,
2,
65536,
PixelType::U16x2,
"Two `u16` components per pixel (e.g. LA16)"
);
@@ -217,7 +248,6 @@ pixel_struct!(
[u16; 3],
u16,
3,
65536,
PixelType::U16x3,
"Three `u16` components per pixel (e.g. RGB16)"
);
@@ -226,7 +256,6 @@ pixel_struct!(
[u16; 4],
u16,
4,
65536,
PixelType::U16x4,
"Four `u16` components per pixel (e.g. RGBA16)"
);
@@ -235,7 +264,6 @@ pixel_struct!(
i32,
i32,
1,
0,
PixelType::I32,
"One `i32` component per pixel"
);
@@ -244,7 +272,6 @@ pixel_struct!(
f32,
f32,
1,
0,
PixelType::F32,
"One `f32` component per pixel"
);
+3 -3
View File
@@ -2,7 +2,7 @@ use std::num::NonZeroU32;
use crate::convolution::{self, Convolution, FilterType};
use crate::image::InnerImage;
use crate::pixels::Pixel;
use crate::pixels::PixelExt;
use crate::{
DifferentTypesOfPixelsError, DynamicImageView, DynamicImageViewMut, ImageView, ImageViewMut,
};
@@ -184,7 +184,7 @@ impl Resizer {
}
}
fn get_temp_image_from_buffer<P: Pixel>(
fn get_temp_image_from_buffer<P: PixelExt>(
buffer: &mut Vec<u8>,
width: NonZeroU32,
height: NonZeroU32,
@@ -201,7 +201,7 @@ fn get_temp_image_from_buffer<P: Pixel>(
fn resample_nearest<P>(src_image: &ImageView<P>, dst_image: &mut ImageViewMut<P>)
where
P: Pixel,
P: PixelExt,
{
let crop_box = src_image.crop_box();
let dst_width = dst_image.width().get();
+11 -11
View File
@@ -27,7 +27,7 @@ pub fn image_u16_checksum<const N: usize>(buffer: &[u8]) -> [u64; N] {
res
}
pub trait PixelExt: Pixel {
pub trait PixelTestingExt: PixelExt {
fn pixel_type_str() -> &'static str {
match Self::pixel_type() {
PixelType::U8 => "u8",
@@ -83,13 +83,13 @@ pub trait PixelExt: Pixel {
fn img_into_bytes(img: DynamicImage) -> Vec<u8>;
}
impl PixelExt for U8 {
impl PixelTestingExt for U8 {
fn img_into_bytes(img: DynamicImage) -> Vec<u8> {
img.to_luma8().into_raw()
}
}
impl PixelExt for U8x2 {
impl PixelTestingExt for U8x2 {
fn load_big_image() -> DynamicImage {
ImageReader::open("./data/nasa-4928x3279-rgba.png")
.unwrap()
@@ -109,13 +109,13 @@ impl PixelExt for U8x2 {
}
}
impl PixelExt for U8x3 {
impl PixelTestingExt for U8x3 {
fn img_into_bytes(img: DynamicImage) -> Vec<u8> {
img.to_rgb8().into_raw()
}
}
impl PixelExt for U8x4 {
impl PixelTestingExt for U8x4 {
fn load_big_image() -> DynamicImage {
ImageReader::open("./data/nasa-4928x3279-rgba.png")
.unwrap()
@@ -135,7 +135,7 @@ impl PixelExt for U8x4 {
}
}
impl PixelExt for U16 {
impl PixelTestingExt for U16 {
fn img_into_bytes(img: DynamicImage) -> Vec<u8> {
// img.to_luma16()
// .as_raw()
@@ -152,7 +152,7 @@ impl PixelExt for U16 {
}
}
impl PixelExt for U16x2 {
impl PixelTestingExt for U16x2 {
fn load_big_image() -> DynamicImage {
ImageReader::open("./data/nasa-4928x3279-rgba.png")
.unwrap()
@@ -176,7 +176,7 @@ impl PixelExt for U16x2 {
}
}
impl PixelExt for U16x3 {
impl PixelTestingExt for U16x3 {
fn img_into_bytes(img: DynamicImage) -> Vec<u8> {
img.to_rgb8()
.as_raw()
@@ -186,7 +186,7 @@ impl PixelExt for U16x3 {
}
}
impl PixelExt for U16x4 {
impl PixelTestingExt for U16x4 {
fn load_big_image() -> DynamicImage {
ImageReader::open("./data/nasa-4928x3279-rgba.png")
.unwrap()
@@ -210,7 +210,7 @@ impl PixelExt for U16x4 {
}
}
impl PixelExt for I32 {
impl PixelTestingExt for I32 {
fn img_into_bytes(img: DynamicImage) -> Vec<u8> {
img.to_luma16()
.as_raw()
@@ -221,7 +221,7 @@ impl PixelExt for I32 {
}
}
impl PixelExt for F32 {
impl PixelTestingExt for F32 {
fn img_into_bytes(img: DynamicImage) -> Vec<u8> {
img.to_luma16()
.as_raw()
+64 -64
View File
@@ -1,17 +1,17 @@
use std::num::NonZeroU32;
use fast_image_resize::pixels::{Pixel, U16x2, U16x4, U8x2, U8x4};
use fast_image_resize::pixels::{PixelExt, U16x2, U16x4, U8x2, U8x4};
use fast_image_resize::{
CpuExtensions, DynamicImageView, DynamicImageViewMut, Image, ImageView, ImageViewMut, MulDiv,
PixelType,
};
const fn p2(l: u8, a: u8) -> U8x2 {
U8x2(u16::from_le_bytes([l, a]))
U8x2::new(u16::from_le_bytes([l, a]))
}
const fn p4(r: u8, g: u8, b: u8, a: u8) -> U8x4 {
U8x4(u32::from_le_bytes([r, g, b, a]))
U8x4::new(u32::from_le_bytes([r, g, b, a]))
}
enum Oper {
@@ -23,7 +23,7 @@ enum Oper {
fn mul_div_alpha_test<P>(oper: Oper, src_pixel: P, result_pixel: P, cpu_extensions: CpuExtensions)
where
P: Pixel + 'static,
P: PixelExt + 'static,
for<'a> ImageView<'a, P>: Into<DynamicImageView<'a>>,
for<'a> ImageViewMut<'a, P>: Into<DynamicImageViewMut<'a>>,
{
@@ -189,26 +189,26 @@ mod multiply_alpha_u16x2 {
use fast_image_resize::pixels::U16x2;
const SRC_PIXELS: [U16x2; 9] = [
U16x2([0xffff, 0x8000]),
U16x2([0x8000, 0x8000]),
U16x2([0, 0x8000]),
U16x2([0xffff, 0xffff]),
U16x2([0x8000, 0xffff]),
U16x2([0, 0xffff]),
U16x2([0xffff, 0]),
U16x2([0x8000, 0]),
U16x2([0, 0]),
U16x2::new([0xffff, 0x8000]),
U16x2::new([0x8000, 0x8000]),
U16x2::new([0, 0x8000]),
U16x2::new([0xffff, 0xffff]),
U16x2::new([0x8000, 0xffff]),
U16x2::new([0, 0xffff]),
U16x2::new([0xffff, 0]),
U16x2::new([0x8000, 0]),
U16x2::new([0, 0]),
];
const RES_PIXELS: [U16x2; 9] = [
U16x2([0x8000, 0x8000]),
U16x2([0x4000, 0x8000]),
U16x2([0, 0x8000]),
U16x2([0xffff, 0xffff]),
U16x2([0x8000, 0xffff]),
U16x2([0, 0xffff]),
U16x2([0, 0]),
U16x2([0, 0]),
U16x2([0, 0]),
U16x2::new([0x8000, 0x8000]),
U16x2::new([0x4000, 0x8000]),
U16x2::new([0, 0x8000]),
U16x2::new([0xffff, 0xffff]),
U16x2::new([0x8000, 0xffff]),
U16x2::new([0, 0xffff]),
U16x2::new([0, 0]),
U16x2::new([0, 0]),
U16x2::new([0, 0]),
];
#[cfg(target_arch = "x86_64")]
@@ -241,14 +241,14 @@ mod multiply_alpha_u16x4 {
use fast_image_resize::pixels::U16x4;
const SRC_PIXELS: [U16x4; 3] = [
U16x4([0xffff, 0x8000, 0, 0x8000]),
U16x4([0xffff, 0x8000, 0, 0xffff]),
U16x4([0xffff, 0x8000, 0, 0]),
U16x4::new([0xffff, 0x8000, 0, 0x8000]),
U16x4::new([0xffff, 0x8000, 0, 0xffff]),
U16x4::new([0xffff, 0x8000, 0, 0]),
];
const RES_PIXELS: [U16x4; 3] = [
U16x4([0x8000, 0x4000, 0, 0x8000]),
U16x4([0xffff, 0x8000, 0, 0xffff]),
U16x4([0, 0, 0, 0]),
U16x4::new([0x8000, 0x4000, 0, 0x8000]),
U16x4::new([0xffff, 0x8000, 0, 0xffff]),
U16x4::new([0, 0, 0, 0]),
];
#[cfg(target_arch = "x86_64")]
@@ -371,37 +371,37 @@ mod divide_alpha_u16x2 {
const OPER: Oper = Oper::Div;
const SRC_PIXELS: [U16x2; 9] = [
U16x2([0x8000, 0x8000]),
U16x2([0x4000, 0x8000]),
U16x2([0, 0x8000]),
U16x2([0xffff, 0xffff]),
U16x2([0x8000, 0xffff]),
U16x2([0, 0xffff]),
U16x2([0xffff, 0]),
U16x2([0x8000, 0]),
U16x2([0, 0]),
U16x2::new([0x8000, 0x8000]),
U16x2::new([0x4000, 0x8000]),
U16x2::new([0, 0x8000]),
U16x2::new([0xffff, 0xffff]),
U16x2::new([0x8000, 0xffff]),
U16x2::new([0, 0xffff]),
U16x2::new([0xffff, 0]),
U16x2::new([0x8000, 0]),
U16x2::new([0, 0]),
];
const RES_PIXELS: [U16x2; 9] = [
U16x2([0xffff, 0x8000]),
U16x2([0x7fff, 0x8000]),
U16x2([0, 0x8000]),
U16x2([0xffff, 0xffff]),
U16x2([0x8000, 0xffff]),
U16x2([0, 0xffff]),
U16x2([0, 0]),
U16x2([0, 0]),
U16x2([0, 0]),
U16x2::new([0xffff, 0x8000]),
U16x2::new([0x7fff, 0x8000]),
U16x2::new([0, 0x8000]),
U16x2::new([0xffff, 0xffff]),
U16x2::new([0x8000, 0xffff]),
U16x2::new([0, 0xffff]),
U16x2::new([0, 0]),
U16x2::new([0, 0]),
U16x2::new([0, 0]),
];
const SIMD_RES_PIXELS: [U16x2; 9] = [
U16x2([0xffff, 0x8000]),
U16x2([0x8000, 0x8000]),
U16x2([0, 0x8000]),
U16x2([0xffff, 0xffff]),
U16x2([0x8000, 0xffff]),
U16x2([0, 0xffff]),
U16x2([0, 0]),
U16x2([0, 0]),
U16x2([0, 0]),
U16x2::new([0xffff, 0x8000]),
U16x2::new([0x8000, 0x8000]),
U16x2::new([0, 0x8000]),
U16x2::new([0xffff, 0xffff]),
U16x2::new([0x8000, 0xffff]),
U16x2::new([0, 0xffff]),
U16x2::new([0, 0]),
U16x2::new([0, 0]),
U16x2::new([0, 0]),
];
#[cfg(target_arch = "x86_64")]
@@ -434,19 +434,19 @@ mod divide_alpha_u16x4 {
const OPER: Oper = Oper::Div;
const SRC_PIXELS: [U16x4; 3] = [
U16x4([0x8000, 0x4000, 0, 0x8000]),
U16x4([0xffff, 0x8000, 0, 0xffff]),
U16x4([0xffff, 0x8000, 0, 0]),
U16x4::new([0x8000, 0x4000, 0, 0x8000]),
U16x4::new([0xffff, 0x8000, 0, 0xffff]),
U16x4::new([0xffff, 0x8000, 0, 0]),
];
const RES_PIXELS: [U16x4; 3] = [
U16x4([0xffff, 0x7fff, 0, 0x8000]),
U16x4([0xffff, 0x8000, 0, 0xffff]),
U16x4([0, 0, 0, 0]),
U16x4::new([0xffff, 0x7fff, 0, 0x8000]),
U16x4::new([0xffff, 0x8000, 0, 0xffff]),
U16x4::new([0, 0, 0, 0]),
];
const SIMD_RES_PIXELS: [U16x4; 3] = [
U16x4([0xffff, 0x8000, 0, 0x8000]),
U16x4([0xffff, 0x8000, 0, 0xffff]),
U16x4([0, 0, 0, 0]),
U16x4::new([0xffff, 0x8000, 0, 0x8000]),
U16x4::new([0xffff, 0x8000, 0, 0xffff]),
U16x4::new([0, 0, 0, 0]),
];
#[cfg(target_arch = "x86_64")]
+9 -3
View File
@@ -5,7 +5,7 @@ use fast_image_resize::{
CpuExtensions, CropBox, DifferentTypesOfPixelsError, DynamicImageView, FilterType, Image,
PixelType, ResizeAlg, Resizer,
};
use testing::{nonzero, PixelExt};
use testing::{nonzero, PixelTestingExt};
fn get_new_height(src_image: &DynamicImageView, new_width: u32) -> u32 {
let scale = new_width as f32 / src_image.width().get() as f32;
@@ -82,7 +82,10 @@ fn resize_to_same_size_after_cropping() {
assert!(matches!(cropped_buffer.cmp(&dst_buffer), Ordering::Equal));
}
fn downscale_test<P: PixelExt>(resize_alg: ResizeAlg, cpu_extensions: CpuExtensions) -> Vec<u8> {
fn downscale_test<P: PixelTestingExt>(
resize_alg: ResizeAlg,
cpu_extensions: CpuExtensions,
) -> Vec<u8> {
let image = P::load_big_src_image();
assert_eq!(image.pixel_type(), P::pixel_type());
@@ -120,7 +123,10 @@ fn downscale_test<P: PixelExt>(resize_alg: ResizeAlg, cpu_extensions: CpuExtensi
result.buffer().to_owned()
}
fn upscale_test<P: PixelExt>(resize_alg: ResizeAlg, cpu_extensions: CpuExtensions) -> Vec<u8> {
fn upscale_test<P: PixelTestingExt>(
resize_alg: ResizeAlg,
cpu_extensions: CpuExtensions,
) -> Vec<u8> {
let image = P::load_small_src_image();
assert_eq!(image.pixel_type(), P::pixel_type());