Fixed resizing when the destination image has the same dimensions as the source image (#9).

This commit is contained in:
Kirill Kuzminykh
2022-07-14 23:29:45 +03:00
parent 8a159fc3e6
commit 6483439ab3
75 changed files with 751 additions and 785 deletions
+6
View File
@@ -1,3 +1,9 @@
## [Unreleased] - ReleaseDate
- Fixed resizing when the destination image has the same dimensions
as the source image
([#9](https://github.com/Cykooz/fast_image_resize/issues/9)).
## [0.9.6] - 2022-06-28
- Added support of new type of pixels `PixelType::U16x4`.
Generated
+62 -39
View File
@@ -39,9 +39,9 @@ checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704"
[[package]]
name = "argh"
version = "0.1.7"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbb41d85d92dfab96cb95ab023c265c5e4261bb956c0fb49ca06d90c570f1958"
checksum = "a7e7e4aa7e40747e023c0761dafcb42333a9517575bbf1241747f68dd3177a62"
dependencies = [
"argh_derive",
"argh_shared",
@@ -49,9 +49,9 @@ dependencies = [
[[package]]
name = "argh_derive"
version = "0.1.7"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be69f70ef5497dd6ab331a50bd95c6ac6b8f7f17a7967838332743fbd58dc3b5"
checksum = "69f2bd7ff6ed6414f4e5521bd509bae46454bbd513801767ced3f21a751ab4bc"
dependencies = [
"argh_shared",
"heck",
@@ -62,9 +62,9 @@ dependencies = [
[[package]]
name = "argh_shared"
version = "0.1.7"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6f8c380fa28aa1b36107cd97f0196474bb7241bb95a453c5c01a15ac74b2eac"
checksum = "47253b98986dafc7a3e1cf3259194f1f47ac61abb57a57f46ec09e48d004ecda"
[[package]]
name = "autocfg"
@@ -110,9 +110,9 @@ checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3"
[[package]]
name = "bytemuck"
version = "1.9.1"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdead85bdec19c194affaeeb670c0e41fe23de31459efd1c174d049269cf02cc"
checksum = "c53dfa917ec274df8ed3c572698f381a24eef2efba9492d797301b72b6db408a"
[[package]]
name = "byteorder"
@@ -151,12 +151,14 @@ dependencies = [
[[package]]
name = "cli-log"
version = "0.1.0"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f47673f2992075892b3e983499410c92af91a7d7cee72cf55ec4caea278de6cf"
checksum = "3d2ab00dc4c82ec28af25ac085aecc11ffeabf353755715a3113a7aa044ca5cc"
dependencies = [
"chrono",
"file-size",
"log",
"proc-status",
]
[[package]]
@@ -301,9 +303,9 @@ dependencies = [
[[package]]
name = "csv2svg"
version = "0.1.7"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5eede96fa4be061f1b49b92c756f8d150de9fbb5b11e09c6c2b3d670e32fd9f5"
checksum = "22bc4e544d47a40c5d62c5583d3df357e40e0a5f5027d38ffc8d4e5c141276a6"
dependencies = [
"anyhow",
"argh",
@@ -316,7 +318,7 @@ dependencies = [
"log",
"num-traits",
"open",
"svg",
"svg 0.10.0",
"tempfile",
]
@@ -352,9 +354,9 @@ dependencies = [
[[package]]
name = "either"
version = "1.6.1"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be"
[[package]]
name = "exr"
@@ -390,7 +392,7 @@ version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c195cf4b2285d3c993eb887b4dc56b0d5728bbe1d0f9a99c0ac6bec2da3e4d85"
dependencies = [
"hashbrown 0.12.1",
"hashbrown 0.12.2",
]
[[package]]
@@ -417,6 +419,12 @@ dependencies = [
"instant",
]
[[package]]
name = "file-size"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9544f10105d33957765016b8a9baea7e689bf1f0f2f32c2fa2f568770c38d2b3"
[[package]]
name = "flate2"
version = "1.0.24"
@@ -514,7 +522,7 @@ dependencies = [
"rusqlite",
"serde",
"serde_json",
"svg",
"svg 0.8.2",
"tempfile",
"termimad",
"thiserror",
@@ -537,9 +545,9 @@ dependencies = [
[[package]]
name = "hashbrown"
version = "0.12.1"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3"
checksum = "607c8a29735385251a339424dd462993c0fed8fa09d378f259377df08c126022"
dependencies = [
"ahash 0.7.6",
]
@@ -855,9 +863,9 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.12.0"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225"
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
[[package]]
name = "open"
@@ -906,18 +914,18 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "pin-project"
version = "1.0.10"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e"
checksum = "78203e83c48cffbe01e4a2d35d566ca4de445d79a85372fc64e378bfc812a260"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.0.10"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb"
checksum = "710faf75e1b33345361201d36d04e98ac1ed8909151a017ed384700836104c74"
dependencies = [
"proc-macro2",
"quote",
@@ -951,6 +959,15 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "proc-status"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0e0c0ac915e7b76b47850ba4ffc377abde6c6ff9eeace61d0a89623db449712"
dependencies = [
"thiserror",
]
[[package]]
name = "quote"
version = "1.0.20"
@@ -1073,18 +1090,18 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "serde"
version = "1.0.137"
version = "1.0.139"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1"
checksum = "0171ebb889e45aa68b44aee0859b3eede84c6f5f5c228e6f140c0b2a0a46cad6"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.137"
version = "1.0.139"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be"
checksum = "dc1d3230c1de7932af58ad8ffbe1d784bd55efd5a9d84ac24f69c72d83543dfb"
dependencies = [
"proc-macro2",
"quote",
@@ -1093,9 +1110,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.81"
version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c"
checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7"
dependencies = [
"itoa 1.0.2",
"ryu",
@@ -1134,15 +1151,15 @@ dependencies = [
[[package]]
name = "smallvec"
version = "1.8.1"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc88c725d61fc6c3132893370cac4a0200e3fedf5da8331c570664b1987f5ca2"
checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
[[package]]
name = "spin"
version = "0.9.3"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c530c2b0d0bf8b69304b39fe2001993e267461948b890cd037d8ad4293fa1a0d"
checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09"
dependencies = [
"lock_api",
]
@@ -1153,6 +1170,12 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3bdb25a4593d6656239319426f4025f7a658157e25e89f0e0319d7516d46042d"
[[package]]
name = "svg"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e72d8b19ab05827afefcca66bf47040c1e66a0901eb814784c77d4ec118bd309"
[[package]]
name = "syn"
version = "1.0.98"
@@ -1280,9 +1303,9 @@ checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c"
[[package]]
name = "unicode-normalization"
version = "0.1.20"
version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81dee68f85cab8cf68dec42158baf3a79a1cdc065a8b103025965d6ccb7f6cbd"
checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6"
dependencies = [
"tinyvec",
]
@@ -1391,9 +1414,9 @@ checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be"
[[package]]
name = "weezl"
version = "0.1.6"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c97e489d8f836838d497091de568cf16b117486d529ec5579233521065bd5e4"
checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb"
[[package]]
name = "winapi"
+14 -14
View File
@@ -49,11 +49,11 @@ Pipeline:
| | Nearest | Bilinear | CatmullRom | Lanczos3 |
|------------|:-------:|:--------:|:----------:|:--------:|
| image | 19.24 | 82.52 | 152.17 | 207.63 |
| resize | - | 52.19 | 103.40 | 154.15 |
| fir rust | 0.28 | 40.88 | 69.39 | 101.53 |
| fir sse4.1 | 0.28 | 28.21 | 43.03 | 59.46 |
| fir avx2 | 0.28 | 7.33 | 9.47 | 13.59 |
| image | 18.75 | 83.16 | 148.86 | 205.11 |
| resize | - | 52.27 | 103.40 | 154.10 |
| fir rust | 0.28 | 41.93 | 76.81 | 114.10 |
| fir sse4.1 | 0.28 | 27.98 | 43.16 | 58.43 |
| fir avx2 | 0.28 | 7.42 | 9.71 | 13.91 |
### Resize RGBA8 image (U8x4) 4928x3279 => 852x567
@@ -68,10 +68,10 @@ Pipeline:
| | Nearest | Bilinear | CatmullRom | Lanczos3 |
|------------|:-------:|:--------:|:----------:|:--------:|
| resize | - | 61.93 | 122.10 | 182.55 |
| fir rust | 0.18 | 36.57 | 52.28 | 74.14 |
| fir sse4.1 | 0.18 | 13.14 | 17.21 | 22.44 |
| fir avx2 | 0.18 | 9.69 | 11.99 | 16.23 |
| resize | - | 61.37 | 122.00 | 181.84 |
| fir rust | 0.18 | 37.42 | 53.36 | 75.87 |
| fir sse4.1 | 0.18 | 13.33 | 17.40 | 22.71 |
| fir avx2 | 0.18 | 9.69 | 12.09 | 16.35 |
### Resize L8 (luma) image (U8) 4928x3279 => 852x567
@@ -85,11 +85,11 @@ Pipeline:
| | Nearest | Bilinear | CatmullRom | Lanczos3 |
|------------|:-------:|:--------:|:----------:|:--------:|
| image | 15.86 | 47.17 | 74.46 | 102.53 |
| resize | - | 17.30 | 35.92 | 61.52 |
| fir rust | 0.15 | 14.10 | 16.20 | 24.12 |
| fir sse4.1 | 0.15 | 11.93 | 12.13 | 18.20 |
| fir avx2 | 0.15 | 6.30 | 4.71 | 7.62 |
| image | 15.48 | 46.20 | 73.56 | 101.74 |
| resize | - | 17.29 | 35.60 | 61.27 |
| fir rust | 0.16 | 13.79 | 15.31 | 22.76 |
| fir sse4.1 | 0.16 | 12.01 | 12.12 | 18.10 |
| fir avx2 | 0.16 | 6.29 | 4.81 | 7.71 |
## Examples
+36 -36
View File
@@ -5,8 +5,8 @@ Environment:
- CPU: AMD Ryzen 9 5950X
- RAM: DDR4 3800 MHz
- Ubuntu 22.04 (linux 5.15.0)
- Rust 1.61.0
- fast_image_resize = "0.9.3"
- Rust 1.62.0
- fast_image_resize = "0.9.7"
- glassbench = "0.3.3"
Other Rust libraries used to compare of resizing speed:
@@ -32,11 +32,11 @@ Pipeline:
| | Nearest | Bilinear | CatmullRom | Lanczos3 |
|------------|:-------:|:--------:|:----------:|:--------:|
| image | 19.50 | 83.55 | 142.66 | 202.49 |
| resize | - | 52.12 | 102.98 | 153.42 |
| fir rust | 0.28 | 40.94 | 69.96 | 100.86 |
| fir sse4.1 | 0.28 | 28.10 | 43.06 | 58.05 |
| fir avx2 | 0.28 | 7.24 | 9.49 | 13.61 |
| image | 18.75 | 83.16 | 148.86 | 205.11 |
| resize | - | 52.27 | 103.40 | 154.10 |
| fir rust | 0.28 | 41.93 | 76.81 | 114.10 |
| fir sse4.1 | 0.28 | 27.98 | 43.16 | 58.43 |
| fir avx2 | 0.28 | 7.42 | 9.71 | 13.91 |
### Resize RGBA8 image (U8x4) 4928x3279 => 852x567
@@ -51,10 +51,10 @@ Pipeline:
| | Nearest | Bilinear | CatmullRom | Lanczos3 |
|------------|:-------:|:--------:|:----------:|:--------:|
| resize | - | 61.96 | 122.09 | 182.24 |
| fir rust | 0.19 | 36.38 | 52.06 | 74.03 |
| fir sse4.1 | 0.19 | 13.37 | 17.44 | 22.63 |
| fir avx2 | 0.19 | 9.76 | 12.18 | 16.30 |
| resize | - | 61.37 | 122.00 | 181.84 |
| fir rust | 0.18 | 37.42 | 53.36 | 75.87 |
| fir sse4.1 | 0.18 | 13.33 | 17.40 | 22.71 |
| fir avx2 | 0.18 | 9.69 | 12.09 | 16.35 |
### Resize L8 (luma) image (U8) 4928x3279 => 852x567
@@ -68,11 +68,11 @@ Pipeline:
| | Nearest | Bilinear | CatmullRom | Lanczos3 |
|------------|:-------:|:--------:|:----------:|:--------:|
| image | 15.95 | 47.09 | 74.65 | 103.92 |
| resize | - | 17.28 | 35.54 | 61.15 |
| fir rust | 0.16 | 14.33 | 16.25 | 24.35 |
| fir sse4.1 | 0.16 | 12.17 | 12.18 | 18.41 |
| fir avx2 | 0.16 | 6.31 | 4.66 | 7.97 |
| image | 15.48 | 46.20 | 73.56 | 101.74 |
| resize | - | 17.29 | 35.60 | 61.27 |
| fir rust | 0.16 | 13.79 | 15.31 | 22.76 |
| fir sse4.1 | 0.16 | 12.01 | 12.12 | 18.10 |
| fir avx2 | 0.16 | 6.29 | 4.81 | 7.71 |
### Resize LA8 (luma with alpha channel) image (U8x2) 4928x3279 => 852x567
@@ -89,9 +89,9 @@ Pipeline:
| | Nearest | Bilinear | CatmullRom | Lanczos3 |
|------------|:-------:|:--------:|:----------:|:--------:|
| fir rust | 0.18 | 25.79 | 30.79 | 42.38 |
| fir sse4.1 | 0.17 | 12.71 | 14.68 | 18.16 |
| fir avx2 | 0.17 | 11.25 | 12.53 | 15.53 |
| fir rust | 0.17 | 25.97 | 31.30 | 43.20 |
| fir sse4.1 | 0.17 | 12.73 | 14.69 | 18.16 |
| fir avx2 | 0.17 | 11.24 | 12.51 | 15.45 |
### Resize RGB16 image (U16x3) 4928x3279 => 852x567
@@ -105,11 +105,11 @@ Pipeline:
| | Nearest | Bilinear | CatmullRom | Lanczos3 |
|------------|:-------:|:--------:|:----------:|:--------:|
| image | 19.09 | 76.86 | 140.93 | 191.14 |
| resize | - | 55.19 | 107.76 | 159.66 |
| fir rust | 0.33 | 43.89 | 80.03 | 117.89 |
| fir sse4.1 | 0.33 | 24.46 | 39.45 | 55.91 |
| fir avx2 | 0.33 | 21.01 | 31.07 | 36.95 |
| image | 18.34 | 75.56 | 136.94 | 186.09 |
| resize | - | 55.09 | 107.12 | 158.71 |
| fir rust | 0.33 | 43.65 | 79.55 | 117.51 |
| fir sse4.1 | 0.33 | 24.39 | 39.47 | 55.81 |
| fir avx2 | 0.33 | 20.79 | 30.79 | 36.76 |
### Resize RGBA16 image (U16x4) 4928x3279 => 852x567
@@ -124,10 +124,10 @@ Pipeline:
| | Nearest | Bilinear | CatmullRom | Lanczos3 |
|------------|:-------:|:--------:|:----------:|:--------:|
| resize | - | 62.92 | 124.11 | 185.29 |
| fir rust | 0.38 | 84.98 | 123.53 | 163.92 |
| fir sse4.1 | 0.38 | 42.35 | 63.57 | 85.62 |
| fir avx2 | 0.38 | 23.60 | 34.29 | 45.60 |
| resize | - | 63.90 | 127.59 | 191.40 |
| fir rust | 0.37 | 87.77 | 125.78 | 165.53 |
| fir sse4.1 | 0.37 | 42.54 | 63.71 | 85.59 |
| fir avx2 | 0.37 | 23.43 | 34.04 | 45.37 |
### Resize L16 image (U16) 4928x3279 => 852x567
@@ -141,11 +141,11 @@ Pipeline:
| | Nearest | Bilinear | CatmullRom | Lanczos3 |
|------------|:-------:|:--------:|:----------:|:--------:|
| image | 16.43 | 48.12 | 75.85 | 104.63 |
| resize | - | 15.48 | 32.05 | 57.16 |
| fir rust | 0.17 | 19.31 | 26.93 | 37.76 |
| fir sse4.1 | 0.18 | 7.87 | 13.22 | 19.26 |
| fir avx2 | 0.18 | 7.17 | 9.62 | 14.73 |
| image | 15.70 | 45.79 | 73.63 | 103.38 |
| resize | - | 15.52 | 32.13 | 57.22 |
| fir rust | 0.17 | 18.51 | 27.75 | 38.42 |
| fir sse4.1 | 0.17 | 7.77 | 13.21 | 19.16 |
| fir avx2 | 0.17 | 7.07 | 9.54 | 14.81 |
### Resize LA16 (luma with alpha channel) image (U16x2) 4928x3279 => 852x567
@@ -162,6 +162,6 @@ Pipeline:
| | Nearest | Bilinear | CatmullRom | Lanczos3 |
|------------|:-------:|:--------:|:----------:|:--------:|
| fir rust | 0.19 | 34.70 | 54.59 | 74.64 |
| fir sse4.1 | 0.19 | 22.71 | 34.82 | 47.46 |
| fir avx2 | 0.20 | 15.68 | 22.42 | 29.13 |
| fir rust | 0.19 | 33.85 | 53.43 | 72.17 |
| fir sse4.1 | 0.19 | 21.92 | 34.05 | 46.44 |
| fir avx2 | 0.19 | 15.16 | 21.93 | 28.98 |
+1 -1
View File
@@ -1,7 +1,7 @@
pub use errors::*;
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::Pixel;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
use crate::CpuExtensions;
mod common;
+1 -1
View File
@@ -1,7 +1,7 @@
use std::arch::x86_64::*;
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U16x2;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
use super::sse4;
+1 -1
View File
@@ -1,5 +1,5 @@
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U16x2;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
use crate::CpuExtensions;
use super::AlphaMulDiv;
+1 -1
View File
@@ -1,6 +1,6 @@
use crate::alpha::common::{div_and_clip16, mul_div_65535, RECIP_ALPHA16};
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U16x2;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
pub(crate) fn multiply_alpha(
src_image: TypedImageView<U16x2>,
+1 -1
View File
@@ -1,7 +1,7 @@
use std::arch::x86_64::*;
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U16x2;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
use super::native;
+1 -1
View File
@@ -1,7 +1,7 @@
use std::arch::x86_64::*;
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U16x4;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
use super::sse4;
+1 -1
View File
@@ -1,5 +1,5 @@
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U16x4;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
use crate::CpuExtensions;
use super::AlphaMulDiv;
+1 -1
View File
@@ -1,6 +1,6 @@
use crate::alpha::common::{div_and_clip16, mul_div_65535, RECIP_ALPHA16};
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U16x4;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
pub(crate) fn multiply_alpha(
src_image: TypedImageView<U16x4>,
+1 -1
View File
@@ -1,7 +1,7 @@
use std::arch::x86_64::*;
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U16x4;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
use super::native;
+3 -2
View File
@@ -1,9 +1,10 @@
use std::arch::x86_64::*;
use super::sse4;
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U8x2;
use crate::simd_utils;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
use super::sse4;
#[target_feature(enable = "avx2")]
pub(crate) unsafe fn multiply_alpha(
+2 -2
View File
@@ -1,6 +1,6 @@
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U8x2;
use crate::CpuExtensions;
use crate::pixels::U8x2;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
use super::AlphaMulDiv;
+1 -1
View File
@@ -1,6 +1,6 @@
use crate::alpha::common::{div_and_clip, mul_div_255, RECIP_ALPHA};
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U8x2;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
pub(crate) fn multiply_alpha(
src_image: TypedImageView<U8x2>,
+1 -1
View File
@@ -1,7 +1,7 @@
use std::arch::x86_64::*;
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U8x2;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
use super::native;
+3 -2
View File
@@ -1,9 +1,10 @@
use std::arch::x86_64::*;
use super::{native, sse4};
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U8x4;
use crate::simd_utils;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
use super::{native, sse4};
#[target_feature(enable = "avx2")]
pub(crate) unsafe fn multiply_alpha(
+1 -1
View File
@@ -1,5 +1,5 @@
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U8x4;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
use crate::CpuExtensions;
use super::AlphaMulDiv;
+1 -1
View File
@@ -1,6 +1,6 @@
use crate::alpha::common::{div_and_clip, mul_div_255, RECIP_ALPHA};
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U8x4;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
pub(crate) fn multiply_alpha(
src_image: TypedImageView<U8x4>,
+1 -1
View File
@@ -1,7 +1,7 @@
use std::arch::x86_64::*;
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U8x4;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
use super::native;
+3 -2
View File
@@ -1,8 +1,9 @@
use super::{Coefficients, Convolution};
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::F32;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
use crate::CpuExtensions;
use super::{Coefficients, Convolution};
mod native;
impl Convolution for F32 {
+1 -1
View File
@@ -1,6 +1,6 @@
use crate::convolution::Coefficients;
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::F32;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
pub(crate) fn horiz_convolution(
src_image: TypedImageView<F32>,
+3 -2
View File
@@ -1,8 +1,9 @@
use super::{Coefficients, Convolution};
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::I32;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
use crate::CpuExtensions;
use super::{Coefficients, Convolution};
mod native;
impl Convolution for I32 {
+1 -1
View File
@@ -1,6 +1,6 @@
use crate::convolution::Coefficients;
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::I32;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
pub(crate) fn horiz_convolution(
src_image: TypedImageView<I32>,
+4 -3
View File
@@ -1,10 +1,11 @@
use std::num::NonZeroU32;
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::Pixel;
use crate::CpuExtensions;
pub use filters::{get_filter_func, FilterType};
use crate::pixels::Pixel;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
use crate::CpuExtensions;
#[macro_use]
mod macros;
+2 -1
View File
@@ -1,9 +1,10 @@
use std::arch::x86_64::*;
use crate::convolution::{optimisations, Coefficients};
use crate::image_view::{FourRows, FourRowsMut, TypedImageView, TypedImageViewMut};
use crate::image_view::{FourRows, FourRowsMut};
use crate::pixels::U16;
use crate::simd_utils;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
#[inline]
pub(crate) fn horiz_convolution(
+3 -2
View File
@@ -1,9 +1,10 @@
use super::{Coefficients, Convolution};
use crate::convolution::vertical_u16::vert_convolution_u16;
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U16;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
use crate::CpuExtensions;
use super::{Coefficients, Convolution};
#[cfg(target_arch = "x86_64")]
mod avx2;
mod native;
+1 -1
View File
@@ -1,6 +1,6 @@
use crate::convolution::{optimisations, Coefficients};
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U16;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
#[inline(always)]
pub(crate) fn horiz_convolution(
+2 -1
View File
@@ -1,9 +1,10 @@
use std::arch::x86_64::*;
use crate::convolution::{optimisations, Coefficients};
use crate::image_view::{FourRows, FourRowsMut, TypedImageView, TypedImageViewMut};
use crate::image_view::{FourRows, FourRowsMut};
use crate::pixels::U16;
use crate::simd_utils;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
#[inline]
pub(crate) fn horiz_convolution(
+2 -1
View File
@@ -1,9 +1,10 @@
use std::arch::x86_64::*;
use crate::convolution::{optimisations, Coefficients};
use crate::image_view::{FourRows, FourRowsMut, TypedImageView, TypedImageViewMut};
use crate::image_view::{FourRows, FourRowsMut};
use crate::pixels::U16x2;
use crate::simd_utils;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
#[inline]
pub(crate) fn horiz_convolution(
+3 -2
View File
@@ -1,9 +1,10 @@
use super::{Coefficients, Convolution};
use crate::convolution::vertical_u16::vert_convolution_u16;
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U16x2;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
use crate::CpuExtensions;
use super::{Coefficients, Convolution};
#[cfg(target_arch = "x86_64")]
mod avx2;
mod native;
+1 -1
View File
@@ -1,6 +1,6 @@
use crate::convolution::{optimisations, Coefficients};
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U16x2;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
#[inline(always)]
pub(crate) fn horiz_convolution(
+2 -1
View File
@@ -1,9 +1,10 @@
use std::arch::x86_64::*;
use crate::convolution::{optimisations, Coefficients};
use crate::image_view::{FourRows, FourRowsMut, TypedImageView, TypedImageViewMut};
use crate::image_view::{FourRows, FourRowsMut};
use crate::pixels::U16x2;
use crate::simd_utils;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
#[inline]
pub(crate) fn horiz_convolution(
+2 -1
View File
@@ -1,9 +1,10 @@
use std::arch::x86_64::*;
use crate::convolution::{optimisations, Coefficients};
use crate::image_view::{FourRows, FourRowsMut, TypedImageView, TypedImageViewMut};
use crate::image_view::{FourRows, FourRowsMut};
use crate::pixels::U16x3;
use crate::simd_utils;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
#[inline]
pub(crate) fn horiz_convolution(
+3 -2
View File
@@ -1,9 +1,10 @@
use super::{Coefficients, Convolution};
use crate::convolution::vertical_u16::vert_convolution_u16;
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U16x3;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
use crate::CpuExtensions;
use super::{Coefficients, Convolution};
#[cfg(target_arch = "x86_64")]
mod avx2;
mod native;
+1 -1
View File
@@ -1,6 +1,6 @@
use crate::convolution::{optimisations, Coefficients};
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U16x3;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
#[inline(always)]
pub(crate) fn horiz_convolution(
+2 -1
View File
@@ -2,9 +2,10 @@ use std::arch::x86_64::*;
use crate::convolution::optimisations::CoefficientsI32Chunk;
use crate::convolution::{optimisations, Coefficients};
use crate::image_view::{FourRows, FourRowsMut, TypedImageView, TypedImageViewMut};
use crate::image_view::{FourRows, FourRowsMut};
use crate::pixels::U16x3;
use crate::simd_utils;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
#[inline]
pub(crate) fn horiz_convolution(
+2 -1
View File
@@ -1,9 +1,10 @@
use std::arch::x86_64::*;
use crate::convolution::{optimisations, Coefficients};
use crate::image_view::{FourRows, FourRowsMut, TypedImageView, TypedImageViewMut};
use crate::image_view::{FourRows, FourRowsMut};
use crate::pixels::U16x4;
use crate::simd_utils;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
#[inline]
pub(crate) fn horiz_convolution(
+3 -2
View File
@@ -1,9 +1,10 @@
use super::{Coefficients, Convolution};
use crate::convolution::vertical_u16::vert_convolution_u16;
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U16x4;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
use crate::CpuExtensions;
use super::{Coefficients, Convolution};
#[cfg(target_arch = "x86_64")]
mod avx2;
mod native;
+1 -1
View File
@@ -1,6 +1,6 @@
use crate::convolution::{optimisations, Coefficients};
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U16x4;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
#[inline(always)]
pub(crate) fn horiz_convolution(
+2 -1
View File
@@ -1,9 +1,10 @@
use std::arch::x86_64::*;
use crate::convolution::{optimisations, Coefficients};
use crate::image_view::{FourRows, FourRowsMut, TypedImageView, TypedImageViewMut};
use crate::image_view::{FourRows, FourRowsMut};
use crate::pixels::U16x4;
use crate::simd_utils;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
#[inline]
pub(crate) fn horiz_convolution(
+2 -1
View File
@@ -1,9 +1,10 @@
use std::arch::x86_64::*;
use crate::convolution::{optimisations, Coefficients};
use crate::image_view::{FourRows, FourRowsMut, TypedImageView, TypedImageViewMut};
use crate::image_view::{FourRows, FourRowsMut};
use crate::pixels::U8;
use crate::simd_utils;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
#[inline]
pub(crate) fn horiz_convolution(
+3 -2
View File
@@ -1,9 +1,10 @@
use super::{Coefficients, Convolution};
use crate::convolution::vertical_u8::vert_convolution_u8;
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U8;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
use crate::CpuExtensions;
use super::{Coefficients, Convolution};
#[cfg(target_arch = "x86_64")]
mod avx2;
mod native;
+1 -1
View File
@@ -1,6 +1,6 @@
use crate::convolution::{optimisations, Coefficients};
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U8;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
#[inline(always)]
pub(crate) fn horiz_convolution(
+3 -2
View File
@@ -1,9 +1,10 @@
use std::arch::x86_64::*;
use crate::convolution::{optimisations, Coefficients};
use crate::image_view::{FourRows, FourRowsMut, TypedImageView, TypedImageViewMut};
use crate::convolution::{Coefficients, optimisations};
use crate::image_view::{FourRows, FourRowsMut};
use crate::pixels::U8x2;
use crate::simd_utils;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
#[inline]
pub(crate) fn horiz_convolution(
+2 -2
View File
@@ -1,7 +1,7 @@
use crate::convolution::vertical_u8::vert_convolution_u8;
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U8x2;
use crate::CpuExtensions;
use crate::pixels::U8x2;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
use super::{Coefficients, Convolution};
+1 -1
View File
@@ -1,6 +1,6 @@
use crate::convolution::{optimisations, Coefficients};
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U8x2;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
pub(crate) fn horiz_convolution(
src_image: TypedImageView<U8x2>,
+2 -1
View File
@@ -1,9 +1,10 @@
use std::arch::x86_64::*;
use crate::convolution::{optimisations, Coefficients};
use crate::image_view::{FourRows, FourRowsMut, TypedImageView, TypedImageViewMut};
use crate::image_view::{FourRows, FourRowsMut};
use crate::pixels::U8x2;
use crate::simd_utils;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
#[inline]
pub(crate) fn horiz_convolution(
+2 -1
View File
@@ -2,9 +2,10 @@ use std::arch::x86_64::*;
use std::intrinsics::transmute;
use crate::convolution::{optimisations, Coefficients};
use crate::image_view::{FourRows, FourRowsMut, TypedImageView, TypedImageViewMut};
use crate::image_view::{FourRows, FourRowsMut};
use crate::pixels::U8x3;
use crate::simd_utils;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
#[inline]
pub(crate) fn horiz_convolution(
+3 -2
View File
@@ -1,9 +1,10 @@
use super::{Coefficients, Convolution};
use crate::convolution::vertical_u8::vert_convolution_u8;
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U8x3;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
use crate::CpuExtensions;
use super::{Coefficients, Convolution};
#[cfg(target_arch = "x86_64")]
mod avx2;
mod native;
+1 -1
View File
@@ -1,6 +1,6 @@
use crate::convolution::{optimisations, Coefficients};
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U8x3;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
#[inline(always)]
pub(crate) fn horiz_convolution(
+1 -1
View File
@@ -1,6 +1,6 @@
use crate::convolution::Coefficients;
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U8x3;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
use super::native;
+2 -1
View File
@@ -2,9 +2,10 @@ use std::arch::x86_64::*;
use std::intrinsics::transmute;
use crate::convolution::{optimisations, Coefficients};
use crate::image_view::{FourRows, FourRowsMut, TypedImageView, TypedImageViewMut};
use crate::image_view::{FourRows, FourRowsMut};
use crate::pixels::U8x4;
use crate::simd_utils;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
// This code is based on C-implementation from Pillow-SIMD package for Python
// https://github.com/uploadcare/pillow-simd
+3 -2
View File
@@ -1,9 +1,10 @@
use super::{Coefficients, Convolution};
use crate::convolution::vertical_u8::vert_convolution_u8;
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U8x4;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
use crate::CpuExtensions;
use super::{Coefficients, Convolution};
#[cfg(target_arch = "x86_64")]
mod avx2;
mod native;
+1 -1
View File
@@ -1,6 +1,6 @@
use crate::convolution::{optimisations, Coefficients};
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::U8x4;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
pub(crate) fn horiz_convolution(
src_image: TypedImageView<U8x4>,
+2 -1
View File
@@ -2,9 +2,10 @@ use std::arch::x86_64::*;
use std::intrinsics::transmute;
use crate::convolution::{optimisations, Coefficients};
use crate::image_view::{FourRows, FourRowsMut, TypedImageView, TypedImageViewMut};
use crate::image_view::{FourRows, FourRowsMut};
use crate::pixels::U8x4;
use crate::simd_utils;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
// This code is based on C-implementation from Pillow-SIMD package for Python
// https://github.com/uploadcare/pillow-simd
+1 -1
View File
@@ -1,9 +1,9 @@
use std::arch::x86_64::*;
use crate::convolution::{optimisations, Coefficients};
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::Pixel;
use crate::simd_utils;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
pub(crate) fn vert_convolution<T>(
src_image: TypedImageView<T>,
+1 -1
View File
@@ -1,6 +1,6 @@
use crate::convolution::Coefficients;
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::Pixel;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
use crate::CpuExtensions;
#[cfg(target_arch = "x86_64")]
+1 -1
View File
@@ -1,6 +1,6 @@
use crate::convolution::{optimisations, Coefficients};
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::Pixel;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
#[inline(always)]
pub(crate) fn vert_convolution<T: Pixel<Component = u16>>(
+1 -1
View File
@@ -3,9 +3,9 @@ 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::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::Pixel;
use crate::simd_utils;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
pub(crate) fn vert_convolution<T: Pixel<Component = u16>>(
src_image: TypedImageView<T>,
+1 -1
View File
@@ -1,9 +1,9 @@
use std::arch::x86_64::*;
use crate::convolution::{optimisations, Coefficients};
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::Pixel;
use crate::simd_utils;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
#[inline]
pub(crate) fn vert_convolution<T>(
+1 -1
View File
@@ -1,6 +1,6 @@
use crate::convolution::Coefficients;
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::Pixel;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
use crate::CpuExtensions;
#[cfg(target_arch = "x86_64")]
+1 -1
View File
@@ -1,6 +1,6 @@
use crate::convolution::{optimisations, Coefficients};
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::Pixel;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
#[inline(always)]
pub(crate) fn vert_convolution<T>(
+1 -1
View File
@@ -1,9 +1,9 @@
use std::arch::x86_64::*;
use crate::convolution::{optimisations, Coefficients};
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::Pixel;
use crate::simd_utils;
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
#[inline]
pub(crate) fn vert_convolution<T: Pixel<Component = u8>>(
+8 -2
View File
@@ -10,7 +10,7 @@ pub enum ImageRowsError {
#[derive(Error, Debug, Clone, Copy, PartialEq)]
pub enum ImageBufferError {
#[error("Size of buffer is smaller than required.")]
#[error("Size of buffer is smaller than required")]
InvalidBufferSize,
#[error("Alignment of buffer don't match to alignment of u32")]
InvalidBufferAlignment,
@@ -25,5 +25,11 @@ pub enum CropBoxError {
}
#[derive(Error, Debug, Clone, Copy)]
#[error("Type of pixels of the source image is not equal to pixel type of the destination image.")]
#[error("Type of pixels of the source image is not equal to pixel type of the destination image")]
pub struct DifferentTypesOfPixelsError;
#[derive(Error, Debug, Clone, Copy)]
#[error(
"The dimensions of the source image are not equal to the dimensions of the destination image"
)]
pub(crate) struct DifferentDimensionsError;
+2 -1
View File
@@ -1,7 +1,8 @@
use std::num::NonZeroU32;
use crate::image_view::{ImageRows, ImageRowsMut, TypedImageView, TypedImageViewMut};
use crate::image_rows::{ImageRows, ImageRowsMut};
use crate::pixels::{Pixel, PixelType, U16x2, U16x3, U16x4, U8x2, U8x3, U8x4, F32, I32, U16, U8};
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
use crate::{ImageBufferError, ImageView, ImageViewMut};
#[derive(Debug)]
+183
View File
@@ -0,0 +1,183 @@
use std::mem::transmute;
use std::num::NonZeroU32;
use crate::pixels::{Pixel, U16x2, U16x3, U16x4, U8x2, U8x3, U8x4, F32, I32, U16, U8};
use crate::{ImageRowsError, PixelType};
/// An immutable rows of image.
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum ImageRows<'a> {
U8(Vec<&'a [U8]>),
U8x2(Vec<&'a [U8x2]>),
U8x3(Vec<&'a [U8x3]>),
U8x4(Vec<&'a [U8x4]>),
U16(Vec<&'a [U16]>),
U16x2(Vec<&'a [U16x2]>),
U16x3(Vec<&'a [U16x3]>),
U16x4(Vec<&'a [U16x4]>),
I32(Vec<&'a [I32]>),
F32(Vec<&'a [F32]>),
}
impl<'a> ImageRows<'a> {
pub(crate) fn check_size(
&self,
width: NonZeroU32,
height: NonZeroU32,
) -> Result<(), ImageRowsError> {
match self {
ImageRows::U8(rows) => check_rows_count_and_size(width, height, rows),
ImageRows::U8x2(rows) => check_rows_count_and_size(width, height, rows),
ImageRows::U8x3(rows) => check_rows_count_and_size(width, height, rows),
ImageRows::U8x4(rows) => check_rows_count_and_size(width, height, rows),
ImageRows::U16(rows) => check_rows_count_and_size(width, height, rows),
ImageRows::U16x2(rows) => check_rows_count_and_size(width, height, rows),
ImageRows::U16x3(rows) => check_rows_count_and_size(width, height, rows),
ImageRows::U16x4(rows) => check_rows_count_and_size(width, height, rows),
ImageRows::I32(rows) => check_rows_count_and_size(width, height, rows),
ImageRows::F32(rows) => check_rows_count_and_size(width, height, rows),
}
}
pub fn pixel_type(&self) -> PixelType {
match self {
Self::U8(_) => PixelType::U8,
Self::U8x2(_) => PixelType::U8x2,
Self::U8x3(_) => PixelType::U8x3,
Self::U8x4(_) => PixelType::U8x4,
Self::U16(_) => PixelType::U16,
Self::U16x2(_) => PixelType::U16x2,
Self::U16x3(_) => PixelType::U16x3,
Self::U16x4(_) => PixelType::U16x4,
Self::I32(_) => PixelType::I32,
Self::F32(_) => PixelType::F32,
}
}
pub fn typed_rows<P: Pixel>(&self) -> Option<&[&'a [P]]> {
match (P::pixel_type(), self) {
(PixelType::U8, Self::U8(rows)) => Some(unsafe { transmute(rows.as_slice()) }),
(PixelType::U8x2, Self::U8x2(rows)) => Some(unsafe { transmute(rows.as_slice()) }),
(PixelType::U8x3, Self::U8x3(rows)) => Some(unsafe { transmute(rows.as_slice()) }),
(PixelType::U8x4, Self::U8x4(rows)) => Some(unsafe { transmute(rows.as_slice()) }),
(PixelType::U16, Self::U16(rows)) => Some(unsafe { transmute(rows.as_slice()) }),
(PixelType::U16x2, Self::U16x2(rows)) => Some(unsafe { transmute(rows.as_slice()) }),
(PixelType::U16x3, Self::U16x3(rows)) => Some(unsafe { transmute(rows.as_slice()) }),
(PixelType::U16x4, Self::U16x4(rows)) => Some(unsafe { transmute(rows.as_slice()) }),
(PixelType::I32, Self::I32(rows)) => Some(unsafe { transmute(rows.as_slice()) }),
(PixelType::F32, Self::F32(rows)) => Some(unsafe { transmute(rows.as_slice()) }),
_ => None,
}
}
}
/// A mutable rows of image.
#[derive(Debug)]
#[non_exhaustive]
pub enum ImageRowsMut<'a> {
U8(Vec<&'a mut [U8]>),
U8x2(Vec<&'a mut [U8x2]>),
U8x3(Vec<&'a mut [U8x3]>),
U8x4(Vec<&'a mut [U8x4]>),
U16(Vec<&'a mut [U16]>),
U16x2(Vec<&'a mut [U16x2]>),
U16x3(Vec<&'a mut [U16x3]>),
U16x4(Vec<&'a mut [U16x4]>),
I32(Vec<&'a mut [I32]>),
F32(Vec<&'a mut [F32]>),
}
impl<'a> ImageRowsMut<'a> {
pub(crate) fn check_size(
&self,
width: NonZeroU32,
height: NonZeroU32,
) -> Result<(), ImageRowsError> {
match self {
Self::U8x2(rows) => check_rows_count_and_size(width, height, rows),
Self::U8x3(rows) => check_rows_count_and_size(width, height, rows),
Self::U8x4(rows) => check_rows_count_and_size(width, height, rows),
Self::U16(rows) => check_rows_count_and_size(width, height, rows),
Self::U16x2(rows) => check_rows_count_and_size(width, height, rows),
Self::U16x3(rows) => check_rows_count_and_size(width, height, rows),
Self::U16x4(rows) => check_rows_count_and_size(width, height, rows),
Self::I32(rows) => check_rows_count_and_size(width, height, rows),
Self::F32(rows) => check_rows_count_and_size(width, height, rows),
Self::U8(rows) => check_rows_count_and_size(width, height, rows),
}
}
pub fn pixel_type(&self) -> PixelType {
match self {
Self::U8x2(_) => PixelType::U8x2,
Self::U8x3(_) => PixelType::U8x3,
Self::U8x4(_) => PixelType::U8x4,
Self::U16(_) => PixelType::U16,
Self::U16x2(_) => PixelType::U16x2,
Self::U16x3(_) => PixelType::U16x3,
Self::U16x4(_) => PixelType::U16x4,
Self::I32(_) => PixelType::I32,
Self::F32(_) => PixelType::F32,
Self::U8(_) => PixelType::U8,
}
}
pub fn typed_rows<P: Pixel>(&mut self) -> Option<&mut [&'a mut [P]]> {
match (P::pixel_type(), self) {
(PixelType::U8, Self::U8(rows)) => Some(unsafe { transmute(rows.as_mut_slice()) }),
(PixelType::U8x2, Self::U8x2(rows)) => Some(unsafe { transmute(rows.as_mut_slice()) }),
(PixelType::U8x3, Self::U8x3(rows)) => Some(unsafe { transmute(rows.as_mut_slice()) }),
(PixelType::U8x4, Self::U8x4(rows)) => Some(unsafe { transmute(rows.as_mut_slice()) }),
(PixelType::U16, Self::U16(rows)) => Some(unsafe { transmute(rows.as_mut_slice()) }),
(PixelType::U16x2, Self::U16x2(rows)) => {
Some(unsafe { transmute(rows.as_mut_slice()) })
}
(PixelType::U16x3, Self::U16x3(rows)) => {
Some(unsafe { transmute(rows.as_mut_slice()) })
}
(PixelType::U16x4, Self::U16x4(rows)) => {
Some(unsafe { transmute(rows.as_mut_slice()) })
}
(PixelType::I32, Self::I32(rows)) => Some(unsafe { transmute(rows.as_mut_slice()) }),
(PixelType::F32, Self::F32(rows)) => Some(unsafe { transmute(rows.as_mut_slice()) }),
_ => None,
}
}
}
fn check_rows_count_and_size<T>(
width: NonZeroU32,
height: NonZeroU32,
rows: &[impl AsRef<[T]>],
) -> Result<(), ImageRowsError> {
if rows.len() != height.get() as usize {
return Err(ImageRowsError::InvalidRowsCount);
}
let row_size = width.get() as usize;
if rows.iter().any(|row| row.as_ref().len() != row_size) {
return Err(ImageRowsError::InvalidRowSize);
}
Ok(())
}
macro_rules! image_rows_from {
($pixel_type:tt, $enum_type:expr) => {
impl<'a> From<Vec<&'a [$pixel_type]>> for ImageRows<'a> {
fn from(rows: Vec<&'a [$pixel_type]>) -> Self {
$enum_type(rows)
}
}
};
}
image_rows_from!(U8, ImageRows::U8);
image_rows_from!(U8x2, ImageRows::U8x2);
image_rows_from!(U8x3, ImageRows::U8x3);
image_rows_from!(U8x4, ImageRows::U8x4);
image_rows_from!(U16, ImageRows::U16);
image_rows_from!(U16x2, ImageRows::U16x2);
image_rows_from!(U16x3, ImageRows::U16x3);
image_rows_from!(U16x4, ImageRows::U16x4);
image_rows_from!(I32, ImageRows::I32);
image_rows_from!(F32, ImageRows::F32);
+9 -544
View File
@@ -1,8 +1,8 @@
use std::num::NonZeroU32;
use std::slice;
use crate::errors::{CropBoxError, ImageBufferError, ImageRowsError};
use crate::pixels::{Pixel, PixelType, U16x2, U16x3, U16x4, U8x2, U8x3, U8x4, F32, I32, U16, U8};
use crate::image_rows::{ImageRows, ImageRowsMut};
use crate::pixels::{Pixel, PixelType};
pub(crate) type RowMut<'a, 'b, T> = &'a mut &'b mut [T];
pub(crate) type TwoRows<'a, T> = (&'a [T], &'a [T]);
@@ -23,131 +23,6 @@ pub struct CropBox {
pub height: NonZeroU32,
}
/// An immutable rows of image.
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum ImageRows<'a> {
U8(Vec<&'a [U8]>),
U8x2(Vec<&'a [U8x2]>),
U8x3(Vec<&'a [U8x3]>),
U8x4(Vec<&'a [U8x4]>),
U16(Vec<&'a [U16]>),
U16x2(Vec<&'a [U16x2]>),
U16x3(Vec<&'a [U16x3]>),
U16x4(Vec<&'a [U16x4]>),
I32(Vec<&'a [I32]>),
F32(Vec<&'a [F32]>),
}
impl<'a> ImageRows<'a> {
pub(crate) fn check_size(
&self,
width: NonZeroU32,
height: NonZeroU32,
) -> Result<(), ImageRowsError> {
match self {
ImageRows::U8(rows) => check_rows_count_and_size(width, height, rows),
ImageRows::U8x2(rows) => check_rows_count_and_size(width, height, rows),
ImageRows::U8x3(rows) => check_rows_count_and_size(width, height, rows),
ImageRows::U8x4(rows) => check_rows_count_and_size(width, height, rows),
ImageRows::U16(rows) => check_rows_count_and_size(width, height, rows),
ImageRows::U16x2(rows) => check_rows_count_and_size(width, height, rows),
ImageRows::U16x3(rows) => check_rows_count_and_size(width, height, rows),
ImageRows::U16x4(rows) => check_rows_count_and_size(width, height, rows),
ImageRows::I32(rows) => check_rows_count_and_size(width, height, rows),
ImageRows::F32(rows) => check_rows_count_and_size(width, height, rows),
}
}
pub fn pixel_type(&self) -> PixelType {
match self {
Self::U8(_) => PixelType::U8,
Self::U8x2(_) => PixelType::U8x2,
Self::U8x3(_) => PixelType::U8x3,
Self::U8x4(_) => PixelType::U8x4,
Self::U16(_) => PixelType::U16,
Self::U16x2(_) => PixelType::U16x2,
Self::U16x3(_) => PixelType::U16x3,
Self::U16x4(_) => PixelType::U16x4,
Self::I32(_) => PixelType::I32,
Self::F32(_) => PixelType::F32,
}
}
}
macro_rules! image_rows_from {
($pixel_type:tt, $enum_type:expr) => {
impl<'a> From<Vec<&'a [$pixel_type]>> for ImageRows<'a> {
fn from(rows: Vec<&'a [$pixel_type]>) -> Self {
$enum_type(rows)
}
}
};
}
image_rows_from!(U8, ImageRows::U8);
image_rows_from!(U8x2, ImageRows::U8x2);
image_rows_from!(U8x3, ImageRows::U8x3);
image_rows_from!(U8x4, ImageRows::U8x4);
image_rows_from!(U16, ImageRows::U16);
image_rows_from!(U16x2, ImageRows::U16x2);
image_rows_from!(U16x3, ImageRows::U16x3);
image_rows_from!(U16x4, ImageRows::U16x4);
image_rows_from!(I32, ImageRows::I32);
image_rows_from!(F32, ImageRows::F32);
/// A mutable rows of image.
#[derive(Debug)]
#[non_exhaustive]
pub enum ImageRowsMut<'a> {
U8x2(Vec<&'a mut [U8x2]>),
U8x3(Vec<&'a mut [U8x3]>),
U8x4(Vec<&'a mut [U8x4]>),
U16(Vec<&'a mut [U16]>),
U16x2(Vec<&'a mut [U16x2]>),
U16x3(Vec<&'a mut [U16x3]>),
U16x4(Vec<&'a mut [U16x4]>),
I32(Vec<&'a mut [I32]>),
F32(Vec<&'a mut [F32]>),
U8(Vec<&'a mut [U8]>),
}
impl<'a> ImageRowsMut<'a> {
pub(crate) fn check_size(
&self,
width: NonZeroU32,
height: NonZeroU32,
) -> Result<(), ImageRowsError> {
match self {
Self::U8x2(rows) => check_rows_count_and_size(width, height, rows),
Self::U8x3(rows) => check_rows_count_and_size(width, height, rows),
Self::U8x4(rows) => check_rows_count_and_size(width, height, rows),
Self::U16(rows) => check_rows_count_and_size(width, height, rows),
Self::U16x2(rows) => check_rows_count_and_size(width, height, rows),
Self::U16x3(rows) => check_rows_count_and_size(width, height, rows),
Self::U16x4(rows) => check_rows_count_and_size(width, height, rows),
Self::I32(rows) => check_rows_count_and_size(width, height, rows),
Self::F32(rows) => check_rows_count_and_size(width, height, rows),
Self::U8(rows) => check_rows_count_and_size(width, height, rows),
}
}
pub fn pixel_type(&self) -> PixelType {
match self {
Self::U8x2(_) => PixelType::U8x2,
Self::U8x3(_) => PixelType::U8x3,
Self::U8x4(_) => PixelType::U8x4,
Self::U16(_) => PixelType::U16,
Self::U16x2(_) => PixelType::U16x2,
Self::U16x3(_) => PixelType::U16x3,
Self::U16x4(_) => PixelType::U16x4,
Self::I32(_) => PixelType::I32,
Self::F32(_) => PixelType::F32,
Self::U8(_) => PixelType::U8,
}
}
}
/// An immutable view of image data used by resizer as source image.
#[derive(Debug, Clone)]
pub struct ImageView<'a> {
@@ -308,6 +183,11 @@ impl<'a> ImageView<'a> {
self.height
}
#[inline(always)]
pub(crate) fn typed_rows<P: Pixel>(&self) -> Option<&[&'a [P]]> {
self.rows.typed_rows()
}
#[inline(always)]
pub fn crop_box(&self) -> CropBox {
self.crop_box
@@ -387,240 +267,6 @@ impl<'a> ImageView<'a> {
})
.unwrap();
}
pub(crate) fn u8x2_image(&self) -> Option<TypedImageView<U8x2>> {
if let ImageRows::U8x2(ref rows) = self.rows {
Some(TypedImageView {
width: self.width,
height: self.height,
crop_box: self.crop_box,
rows,
})
} else {
None
}
}
pub(crate) fn u8x3_image(&self) -> Option<TypedImageView<U8x3>> {
if let ImageRows::U8x3(ref rows) = self.rows {
Some(TypedImageView {
width: self.width,
height: self.height,
crop_box: self.crop_box,
rows,
})
} else {
None
}
}
pub(crate) fn u8x4_image(&self) -> Option<TypedImageView<U8x4>> {
if let ImageRows::U8x4(ref rows) = self.rows {
Some(TypedImageView {
width: self.width,
height: self.height,
crop_box: self.crop_box,
rows,
})
} else {
None
}
}
pub(crate) fn u16_image(&self) -> Option<TypedImageView<U16>> {
if let ImageRows::U16(ref rows) = self.rows {
Some(TypedImageView {
width: self.width,
height: self.height,
crop_box: self.crop_box,
rows,
})
} else {
None
}
}
pub(crate) fn u16x2_image(&self) -> Option<TypedImageView<U16x2>> {
if let ImageRows::U16x2(ref rows) = self.rows {
Some(TypedImageView {
width: self.width,
height: self.height,
crop_box: self.crop_box,
rows,
})
} else {
None
}
}
pub(crate) fn u16x3_image(&self) -> Option<TypedImageView<U16x3>> {
if let ImageRows::U16x3(ref rows) = self.rows {
Some(TypedImageView {
width: self.width,
height: self.height,
crop_box: self.crop_box,
rows,
})
} else {
None
}
}
pub(crate) fn u16x4_image(&self) -> Option<TypedImageView<U16x4>> {
if let ImageRows::U16x4(ref rows) = self.rows {
Some(TypedImageView {
width: self.width,
height: self.height,
crop_box: self.crop_box,
rows,
})
} else {
None
}
}
pub(crate) fn i32_image(&self) -> Option<TypedImageView<I32>> {
if let ImageRows::I32(ref rows) = self.rows {
Some(TypedImageView {
width: self.width,
height: self.height,
crop_box: self.crop_box,
rows,
})
} else {
None
}
}
pub(crate) fn f32_image(&self) -> Option<TypedImageView<F32>> {
if let ImageRows::F32(ref rows) = self.rows {
Some(TypedImageView {
width: self.width,
height: self.height,
crop_box: self.crop_box,
rows,
})
} else {
None
}
}
pub(crate) fn u8_image(&self) -> Option<TypedImageView<U8>> {
if let ImageRows::U8(ref rows) = self.rows {
Some(TypedImageView {
width: self.width,
height: self.height,
crop_box: self.crop_box,
rows,
})
} else {
None
}
}
}
/// Generic immutable image view.
pub(crate) struct TypedImageView<'a, 'b, P>
where
P: Pixel,
{
width: NonZeroU32,
height: NonZeroU32,
crop_box: CropBox,
rows: &'a [&'b [P]],
}
impl<'a, 'b, P> TypedImageView<'a, 'b, P>
where
P: Pixel,
{
pub fn new(width: NonZeroU32, height: NonZeroU32, rows: &'a [&'b [P]]) -> Self {
Self {
width,
height,
crop_box: CropBox {
left: 0,
top: 0,
width,
height,
},
rows,
}
}
#[inline(always)]
pub fn width(&self) -> NonZeroU32 {
self.width
}
#[inline(always)]
pub fn height(&self) -> NonZeroU32 {
self.height
}
#[inline(always)]
pub fn crop_box(&self) -> CropBox {
self.crop_box
}
#[inline(always)]
pub(crate) fn iter_4_rows<'s>(
&'s self,
start_y: u32,
max_y: u32,
) -> impl Iterator<Item = FourRows<'b, P>> + 's {
let start_y = start_y as usize;
let max_y = max_y.min(self.height.get()) as usize;
let rows = self.rows.get(start_y..max_y).unwrap_or(&[]);
rows.chunks_exact(4).map(|rows| match *rows {
[r0, r1, r2, r3] => (r0, r1, r2, r3),
_ => unreachable!(),
})
}
#[inline(always)]
pub(crate) fn iter_2_rows<'s>(
&'s self,
start_y: u32,
max_y: u32,
) -> impl Iterator<Item = TwoRows<'b, P>> + 's {
let start_y = start_y as usize;
let max_y = max_y.min(self.height.get()) as usize;
let rows = self.rows.get(start_y..max_y).unwrap_or(&[]);
rows.chunks_exact(2).map(|rows| match *rows {
[r0, r1] => (r0, r1),
_ => unreachable!(),
})
}
#[inline(always)]
pub(crate) fn iter_rows<'s>(&'s self, start_y: u32) -> impl Iterator<Item = &'b [P]> + 's {
let start_y = start_y as usize;
let rows = self.rows.get(start_y..).unwrap_or(&[]);
rows.iter().copied()
}
#[inline(always)]
pub(crate) fn get_row(&self, y: u32) -> Option<&'b [P]> {
self.rows.get(y as usize).copied()
}
#[inline(always)]
pub(crate) fn iter_rows_with_step<'s>(
&'s self,
mut y: f64,
step: f64,
max_count: usize,
) -> impl Iterator<Item = &'b [P]> + 's {
let steps = (self.height.get() as f64 - y) / step;
let steps = (steps.max(0.).ceil() as usize).min(max_count);
(0..steps).map(move |_| {
// Safety of value of y guaranteed by calculation of steps count
let row = unsafe { *self.rows.get_unchecked(y as usize) };
y += step;
row
})
}
}
/// A mutable view of image data used by resizer as destination image.
@@ -770,191 +416,10 @@ impl<'a> ImageViewMut<'a> {
self.height
}
pub(crate) fn u8x2_image<'s>(&'s mut self) -> Option<TypedImageViewMut<'s, 'a, U8x2>> {
if let ImageRowsMut::U8x2(rows) = &mut self.rows {
Some(TypedImageViewMut {
width: self.width,
height: self.height,
rows,
})
} else {
None
}
}
pub(crate) fn u8x3_image<'s>(&'s mut self) -> Option<TypedImageViewMut<'s, 'a, U8x3>> {
if let ImageRowsMut::U8x3(rows) = &mut self.rows {
Some(TypedImageViewMut {
width: self.width,
height: self.height,
rows,
})
} else {
None
}
}
pub(crate) fn u8x4_image<'s>(&'s mut self) -> Option<TypedImageViewMut<'s, 'a, U8x4>> {
if let ImageRowsMut::U8x4(rows) = &mut self.rows {
Some(TypedImageViewMut {
width: self.width,
height: self.height,
rows,
})
} else {
None
}
}
pub(crate) fn u16_image<'s>(&'s mut self) -> Option<TypedImageViewMut<'s, 'a, U16>> {
if let ImageRowsMut::U16(rows) = &mut self.rows {
Some(TypedImageViewMut {
width: self.width,
height: self.height,
rows,
})
} else {
None
}
}
pub(crate) fn u16x2_image<'s>(&'s mut self) -> Option<TypedImageViewMut<'s, 'a, U16x2>> {
if let ImageRowsMut::U16x2(rows) = &mut self.rows {
Some(TypedImageViewMut {
width: self.width,
height: self.height,
rows,
})
} else {
None
}
}
pub(crate) fn u16x3_image<'s>(&'s mut self) -> Option<TypedImageViewMut<'s, 'a, U16x3>> {
if let ImageRowsMut::U16x3(rows) = &mut self.rows {
Some(TypedImageViewMut {
width: self.width,
height: self.height,
rows,
})
} else {
None
}
}
pub(crate) fn u16x4_image<'s>(&'s mut self) -> Option<TypedImageViewMut<'s, 'a, U16x4>> {
if let ImageRowsMut::U16x4(rows) = &mut self.rows {
Some(TypedImageViewMut {
width: self.width,
height: self.height,
rows,
})
} else {
None
}
}
pub(crate) fn i32_image<'s>(&'s mut self) -> Option<TypedImageViewMut<'s, 'a, I32>> {
if let ImageRowsMut::I32(rows) = &mut self.rows {
Some(TypedImageViewMut {
width: self.width,
height: self.height,
rows,
})
} else {
None
}
}
pub(crate) fn f32_image<'s>(&'s mut self) -> Option<TypedImageViewMut<'s, 'a, F32>> {
if let ImageRowsMut::F32(rows) = &mut self.rows {
Some(TypedImageViewMut {
width: self.width,
height: self.height,
rows,
})
} else {
None
}
}
pub(crate) fn u8_image<'s>(&'s mut self) -> Option<TypedImageViewMut<'s, 'a, U8>> {
if let ImageRowsMut::U8(rows) = &mut self.rows {
Some(TypedImageViewMut {
width: self.width,
height: self.height,
rows,
})
} else {
None
}
}
}
/// Generic mutable image view.
pub(crate) struct TypedImageViewMut<'a, 'b, P>
where
P: Pixel,
{
width: NonZeroU32,
height: NonZeroU32,
rows: &'a mut [&'b mut [P]],
}
impl<'a, 'b, P> TypedImageViewMut<'a, 'b, P>
where
P: Pixel,
{
pub fn new(width: NonZeroU32, height: NonZeroU32, rows: &'a mut [&'b mut [P]]) -> Self {
Self {
width,
height,
rows,
}
}
#[inline(always)]
pub fn width(&self) -> NonZeroU32 {
self.width
pub(crate) fn typed_rows<P: Pixel>(&mut self) -> Option<&mut [&'a mut [P]]> {
self.rows.typed_rows()
}
#[inline(always)]
pub fn height(&self) -> NonZeroU32 {
self.height
}
#[inline(always)]
pub fn iter_rows_mut(&mut self) -> slice::IterMut<&'b mut [P]> {
self.rows.iter_mut()
}
#[inline(always)]
pub fn iter_4_rows_mut<'s>(&'s mut self) -> impl Iterator<Item = FourRowsMut<'s, 'b, P>> {
self.rows.chunks_exact_mut(4).map(|rows| match rows {
[a, b, c, d] => (a, b, c, d),
_ => unreachable!(),
})
}
#[inline(always)]
pub fn get_row_mut<'s>(&'s mut self, y: u32) -> Option<RowMut<'s, 'b, P>> {
self.rows.get_mut(y as usize)
}
}
fn check_rows_count_and_size<T>(
width: NonZeroU32,
height: NonZeroU32,
rows: &[impl AsRef<[T]>],
) -> Result<(), ImageRowsError> {
if rows.len() != height.get() as usize {
return Err(ImageRowsError::InvalidRowsCount);
}
let row_size = width.get() as usize;
if rows.iter().any(|row| row.as_ref().len() != row_size) {
return Err(ImageRowsError::InvalidRowSize);
}
Ok(())
}
fn align_buffer_to<T>(buffer: &[u8]) -> Result<&[T], ImageBufferError> {
+5 -1
View File
@@ -3,7 +3,9 @@
pub use alpha::errors::*;
pub use convolution::FilterType;
pub use errors::*;
pub use image_view::{CropBox, ImageRows, ImageRowsMut, ImageView, ImageViewMut};
pub use image_rows::ImageRows;
pub use image_rows::ImageRowsMut;
pub use image_view::{CropBox, ImageView, ImageViewMut};
pub use mul_div::MulDiv;
pub use pixels::PixelType;
pub use resizer::{CpuExtensions, ResizeAlg, Resizer};
@@ -14,9 +16,11 @@ mod alpha;
mod convolution;
mod errors;
mod image;
mod image_rows;
mod image_view;
mod mul_div;
pub mod pixels;
mod resizer;
#[cfg(target_arch = "x86_64")]
mod simd_utils;
mod typed_image_view;
+13 -29
View File
@@ -1,6 +1,6 @@
use crate::alpha::AlphaMulDiv;
use crate::image_view::{TypedImageView, TypedImageViewMut};
use crate::pixels::{U16x2, U16x4, U8x2, U8x4};
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
use crate::{
CpuExtensions, ImageView, ImageViewMut, MulDivImageError, MulDivImagesError, PixelType,
};
@@ -175,11 +175,9 @@ fn assert_images_u8x2<'s, 'd, 'da>(
),
MulDivImagesError,
> {
let src_image_u8x2 = src_image
.u8x2_image()
let src_image_u8x2 = TypedImageView::from_image_view(src_image)
.ok_or(MulDivImagesError::UnsupportedPixelType)?;
let dst_image_u8x2 = dst_image
.u8x2_image()
let dst_image_u8x2 = TypedImageViewMut::from_image_view(dst_image)
.ok_or(MulDivImagesError::UnsupportedPixelType)?;
if src_image_u8x2.width() != dst_image_u8x2.width()
|| src_image_u8x2.height() != dst_image_u8x2.height()
@@ -193,9 +191,7 @@ fn assert_images_u8x2<'s, 'd, 'da>(
fn assert_image_u8x2<'a, 'b>(
image: &'a mut ImageViewMut<'b>,
) -> Result<TypedImageViewMut<'a, 'b, U8x2>, MulDivImageError> {
image
.u8x2_image()
.ok_or(MulDivImageError::UnsupportedPixelType)
TypedImageViewMut::from_image_view(image).ok_or(MulDivImageError::UnsupportedPixelType)
}
#[inline]
@@ -209,11 +205,9 @@ fn assert_images_u8x4<'s, 'd, 'da>(
),
MulDivImagesError,
> {
let src_image_u8x4 = src_image
.u8x4_image()
let src_image_u8x4 = TypedImageView::from_image_view(src_image)
.ok_or(MulDivImagesError::UnsupportedPixelType)?;
let dst_image_u8x4 = dst_image
.u8x4_image()
let dst_image_u8x4 = TypedImageViewMut::from_image_view(dst_image)
.ok_or(MulDivImagesError::UnsupportedPixelType)?;
if src_image_u8x4.width() != dst_image_u8x4.width()
|| src_image_u8x4.height() != dst_image_u8x4.height()
@@ -227,9 +221,7 @@ fn assert_images_u8x4<'s, 'd, 'da>(
fn assert_image_u8x4<'a, 'b>(
image: &'a mut ImageViewMut<'b>,
) -> Result<TypedImageViewMut<'a, 'b, U8x4>, MulDivImageError> {
image
.u8x4_image()
.ok_or(MulDivImageError::UnsupportedPixelType)
TypedImageViewMut::from_image_view(image).ok_or(MulDivImageError::UnsupportedPixelType)
}
#[inline]
@@ -243,11 +235,9 @@ fn assert_images_u16x2<'s, 'd, 'da>(
),
MulDivImagesError,
> {
let src_image_u16x2 = src_image
.u16x2_image()
let src_image_u16x2 = TypedImageView::from_image_view(src_image)
.ok_or(MulDivImagesError::UnsupportedPixelType)?;
let dst_image_u16x2 = dst_image
.u16x2_image()
let dst_image_u16x2 = TypedImageViewMut::from_image_view(dst_image)
.ok_or(MulDivImagesError::UnsupportedPixelType)?;
if src_image_u16x2.width() != dst_image_u16x2.width()
|| src_image_u16x2.height() != dst_image_u16x2.height()
@@ -261,9 +251,7 @@ fn assert_images_u16x2<'s, 'd, 'da>(
fn assert_image_u16x2<'a, 'b>(
image: &'a mut ImageViewMut<'b>,
) -> Result<TypedImageViewMut<'a, 'b, U16x2>, MulDivImageError> {
image
.u16x2_image()
.ok_or(MulDivImageError::UnsupportedPixelType)
TypedImageViewMut::from_image_view(image).ok_or(MulDivImageError::UnsupportedPixelType)
}
#[inline]
@@ -277,11 +265,9 @@ fn assert_images_u16x4<'s, 'd, 'da>(
),
MulDivImagesError,
> {
let src_image_u16x4 = src_image
.u16x4_image()
let src_image_u16x4 = TypedImageView::from_image_view(src_image)
.ok_or(MulDivImagesError::UnsupportedPixelType)?;
let dst_image_u16x4 = dst_image
.u16x4_image()
let dst_image_u16x4 = TypedImageViewMut::from_image_view(dst_image)
.ok_or(MulDivImagesError::UnsupportedPixelType)?;
if src_image_u16x4.width() != dst_image_u16x4.width()
|| src_image_u16x4.height() != dst_image_u16x4.height()
@@ -295,9 +281,7 @@ fn assert_images_u16x4<'s, 'd, 'da>(
fn assert_image_u16x4<'a, 'b>(
image: &'a mut ImageViewMut<'b>,
) -> Result<TypedImageViewMut<'a, 'b, U16x4>, MulDivImageError> {
image
.u16x4_image()
.ok_or(MulDivImageError::UnsupportedPixelType)
TypedImageViewMut::from_image_view(image).ok_or(MulDivImageError::UnsupportedPixelType)
}
fn multiply_alpha<P>(
+41 -37
View File
@@ -3,8 +3,9 @@ use std::num::NonZeroU32;
use crate::convolution::{self, Convolution, FilterType};
use crate::errors::DifferentTypesOfPixelsError;
use crate::image::InnerImage;
use crate::image_view::{ImageView, ImageViewMut, TypedImageView, TypedImageViewMut};
use crate::pixels::{Pixel, PixelType};
use crate::image_view::{ImageView, ImageViewMut};
use crate::pixels::{Pixel, PixelType, U16x2, U16x3, U16x4, U8x2, U8x3, U8x4, F32, I32, U16, U8};
use crate::typed_image_view::{TypedImageView, TypedImageViewMut};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CpuExtensions {
@@ -83,73 +84,73 @@ impl Resizer {
return Err(DifferentTypesOfPixelsError);
}
match src_image.pixel_type() {
PixelType::U8 => {
if let Some(src) = TypedImageView::from_image_view(src_image) {
if let Some(dst) = TypedImageViewMut::from_image_view(dst_image) {
self.resize_inner::<U8>(src, dst);
}
}
}
PixelType::U8x2 => {
if let Some(src_rows) = src_image.u8x2_image() {
if let Some(dst_rows) = dst_image.u8x2_image() {
self.resize_inner(src_rows, dst_rows);
if let Some(src) = TypedImageView::from_image_view(src_image) {
if let Some(dst) = TypedImageViewMut::from_image_view(dst_image) {
self.resize_inner::<U8x2>(src, dst);
}
}
}
PixelType::U8x3 => {
if let Some(src_rows) = src_image.u8x3_image() {
if let Some(dst_rows) = dst_image.u8x3_image() {
self.resize_inner(src_rows, dst_rows);
if let Some(src) = TypedImageView::from_image_view(src_image) {
if let Some(dst) = TypedImageViewMut::from_image_view(dst_image) {
self.resize_inner::<U8x3>(src, dst);
}
}
}
PixelType::U8x4 => {
if let Some(src_rows) = src_image.u8x4_image() {
if let Some(dst_rows) = dst_image.u8x4_image() {
self.resize_inner(src_rows, dst_rows);
if let Some(src) = TypedImageView::from_image_view(src_image) {
if let Some(dst) = TypedImageViewMut::from_image_view(dst_image) {
self.resize_inner::<U8x4>(src, dst);
}
}
}
PixelType::U16 => {
if let Some(src_rows) = src_image.u16_image() {
if let Some(dst_rows) = dst_image.u16_image() {
self.resize_inner(src_rows, dst_rows);
if let Some(src) = TypedImageView::from_image_view(src_image) {
if let Some(dst) = TypedImageViewMut::from_image_view(dst_image) {
self.resize_inner::<U16>(src, dst);
}
}
}
PixelType::U16x2 => {
if let Some(src_rows) = src_image.u16x2_image() {
if let Some(dst_rows) = dst_image.u16x2_image() {
self.resize_inner(src_rows, dst_rows);
if let Some(src) = TypedImageView::from_image_view(src_image) {
if let Some(dst) = TypedImageViewMut::from_image_view(dst_image) {
self.resize_inner::<U16x2>(src, dst);
}
}
}
PixelType::U16x3 => {
if let Some(src_rows) = src_image.u16x3_image() {
if let Some(dst_rows) = dst_image.u16x3_image() {
self.resize_inner(src_rows, dst_rows);
if let Some(src) = TypedImageView::from_image_view(src_image) {
if let Some(dst) = TypedImageViewMut::from_image_view(dst_image) {
self.resize_inner::<U16x3>(src, dst);
}
}
}
PixelType::U16x4 => {
if let Some(src_rows) = src_image.u16x4_image() {
if let Some(dst_rows) = dst_image.u16x4_image() {
self.resize_inner(src_rows, dst_rows);
if let Some(src) = TypedImageView::from_image_view(src_image) {
if let Some(dst) = TypedImageViewMut::from_image_view(dst_image) {
self.resize_inner::<U16x4>(src, dst);
}
}
}
PixelType::I32 => {
if let Some(src_rows) = src_image.i32_image() {
if let Some(dst_rows) = dst_image.i32_image() {
self.resize_inner(src_rows, dst_rows);
if let Some(src) = TypedImageView::from_image_view(src_image) {
if let Some(dst) = TypedImageViewMut::from_image_view(dst_image) {
self.resize_inner::<I32>(src, dst);
}
}
}
PixelType::F32 => {
if let Some(src_rows) = src_image.f32_image() {
if let Some(dst_rows) = dst_image.f32_image() {
self.resize_inner(src_rows, dst_rows);
}
}
}
PixelType::U8 => {
if let Some(src_rows) = src_image.u8_image() {
if let Some(dst_rows) = dst_image.u8_image() {
self.resize_inner(src_rows, dst_rows);
if let Some(src) = TypedImageView::from_image_view(src_image) {
if let Some(dst) = TypedImageViewMut::from_image_view(dst_image) {
self.resize_inner::<F32>(src, dst);
}
}
}
@@ -157,10 +158,13 @@ impl Resizer {
Ok(())
}
fn resize_inner<P>(&mut self, src_image: TypedImageView<P>, dst_image: TypedImageViewMut<P>)
fn resize_inner<P>(&mut self, src_image: TypedImageView<P>, mut dst_image: TypedImageViewMut<P>)
where
P: Convolution,
{
if dst_image.copy_from_view(&src_image).is_ok() {
return;
}
match self.algorithm {
ResizeAlg::Nearest => resample_nearest(src_image, dst_image),
ResizeAlg::Convolution(filter_type) => {
+208
View File
@@ -0,0 +1,208 @@
use std::num::NonZeroU32;
use std::slice;
use crate::image_view::{FourRows, FourRowsMut, RowMut, TwoRows};
use crate::pixels::Pixel;
use crate::{CropBox, DifferentDimensionsError, ImageView, ImageViewMut};
/// Generic immutable image view.
pub(crate) struct TypedImageView<'a, 'b, P>
where
P: Pixel,
{
width: NonZeroU32,
height: NonZeroU32,
crop_box: CropBox,
rows: &'a [&'b [P]],
}
impl<'a, 'b, P> TypedImageView<'a, 'b, P>
where
P: Pixel,
{
pub fn new(width: NonZeroU32, height: NonZeroU32, rows: &'a [&'b [P]]) -> Self {
Self {
width,
height,
crop_box: CropBox {
left: 0,
top: 0,
width,
height,
},
rows,
}
}
pub fn from_image_view(image_view: &'a ImageView<'b>) -> Option<Self> {
image_view.typed_rows().map(|typed_rows| Self {
width: image_view.width(),
height: image_view.height(),
crop_box: image_view.crop_box(),
rows: typed_rows,
})
}
#[inline(always)]
pub fn width(&self) -> NonZeroU32 {
self.width
}
#[inline(always)]
pub fn height(&self) -> NonZeroU32 {
self.height
}
#[inline(always)]
pub fn crop_box(&self) -> CropBox {
self.crop_box
}
#[inline(always)]
pub(crate) fn iter_4_rows<'s>(
&'s self,
start_y: u32,
max_y: u32,
) -> impl Iterator<Item = FourRows<'b, P>> + 's {
let start_y = start_y as usize;
let max_y = max_y.min(self.height.get()) as usize;
let rows = self.rows.get(start_y..max_y).unwrap_or(&[]);
rows.chunks_exact(4).map(|rows| match *rows {
[r0, r1, r2, r3] => (r0, r1, r2, r3),
_ => unreachable!(),
})
}
#[inline(always)]
pub(crate) fn iter_2_rows<'s>(
&'s self,
start_y: u32,
max_y: u32,
) -> impl Iterator<Item = TwoRows<'b, P>> + 's {
let start_y = start_y as usize;
let max_y = max_y.min(self.height.get()) as usize;
let rows = self.rows.get(start_y..max_y).unwrap_or(&[]);
rows.chunks_exact(2).map(|rows| match *rows {
[r0, r1] => (r0, r1),
_ => unreachable!(),
})
}
#[inline(always)]
pub(crate) fn iter_rows<'s>(&'s self, start_y: u32) -> impl Iterator<Item = &'b [P]> + 's {
let start_y = start_y as usize;
let rows = self.rows.get(start_y..).unwrap_or(&[]);
rows.iter().copied()
}
#[inline(always)]
pub(crate) fn get_row(&self, y: u32) -> Option<&'b [P]> {
self.rows.get(y as usize).copied()
}
#[inline(always)]
pub(crate) fn iter_rows_with_step<'s>(
&'s self,
mut y: f64,
step: f64,
max_count: usize,
) -> impl Iterator<Item = &'b [P]> + 's {
let steps = (self.height.get() as f64 - y) / step;
let steps = (steps.max(0.).ceil() as usize).min(max_count);
(0..steps).map(move |_| {
// Safety of value of y guaranteed by calculation of steps count
let row = unsafe { *self.rows.get_unchecked(y as usize) };
y += step;
row
})
}
#[inline(always)]
pub(crate) fn iter_cropped_rows<'s>(&'s self) -> impl Iterator<Item = &'b [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;
rows.iter()
.map(move |row| unsafe { row.get_unchecked(first_col..last_col) })
}
}
/// Generic mutable image view.
pub(crate) struct TypedImageViewMut<'a, 'b, P>
where
P: Pixel,
{
width: NonZeroU32,
height: NonZeroU32,
rows: &'a mut [&'b mut [P]],
}
impl<'a, 'b, P> TypedImageViewMut<'a, 'b, P>
where
P: Pixel,
{
pub fn new(width: NonZeroU32, height: NonZeroU32, rows: &'a mut [&'b mut [P]]) -> Self {
Self {
width,
height,
rows,
}
}
pub fn from_image_view(image_view: &'a mut ImageViewMut<'b>) -> Option<Self> {
let width = image_view.width();
let height = image_view.height();
image_view.typed_rows().map(|typed_rows| Self {
width,
height,
rows: typed_rows,
})
}
#[inline(always)]
pub fn width(&self) -> NonZeroU32 {
self.width
}
#[inline(always)]
pub fn height(&self) -> NonZeroU32 {
self.height
}
#[inline(always)]
pub fn iter_rows_mut(&mut self) -> slice::IterMut<&'b mut [P]> {
self.rows.iter_mut()
}
#[inline(always)]
pub fn iter_4_rows_mut<'s>(&'s mut self) -> impl Iterator<Item = FourRowsMut<'s, 'b, P>> {
self.rows.chunks_exact_mut(4).map(|rows| match rows {
[a, b, c, d] => (a, b, c, d),
_ => unreachable!(),
})
}
#[inline(always)]
pub fn get_row_mut<'s>(&'s mut self, y: u32) -> Option<RowMut<'s, 'b, P>> {
self.rows.get_mut(y as usize)
}
/// Copy into the view pixels from src_view.
pub(crate) fn copy_from_view(
&mut self,
src_view: &TypedImageView<P>,
) -> Result<(), DifferentDimensionsError> {
let src_crop_box = src_view.crop_box();
if self.width != src_crop_box.width || self.height != src_crop_box.height {
return Err(DifferentDimensionsError);
}
self.rows
.iter_mut()
.zip(src_view.iter_cropped_rows())
.for_each(|(d, s)| d.copy_from_slice(s));
Ok(())
}
}
+2 -3
View File
@@ -1,9 +1,8 @@
use std::num::NonZeroU32;
use fast_image_resize::pixels::{Pixel, U16x2, U16x4, U8x2, U8x4};
use fast_image_resize::{
CpuExtensions, Image, ImageRows, ImageRowsMut, ImageView, ImageViewMut, MulDiv, PixelType,
};
use fast_image_resize::{CpuExtensions, Image, ImageView, ImageViewMut, MulDiv, PixelType};
use fast_image_resize::{ImageRows, ImageRowsMut};
trait IntoImageRows
where
+59 -2
View File
@@ -1,9 +1,10 @@
use std::cmp::Ordering;
use std::num::NonZeroU32;
use fast_image_resize::pixels::*;
use fast_image_resize::{
CpuExtensions, DifferentTypesOfPixelsError, FilterType, Image, ImageView, PixelType, ResizeAlg,
Resizer,
CpuExtensions, CropBox, DifferentTypesOfPixelsError, FilterType, Image, ImageView, PixelType,
ResizeAlg, Resizer,
};
use testing::PixelExt;
@@ -30,6 +31,62 @@ fn try_resize_to_other_pixel_type() {
));
}
#[test]
fn resize_to_same_size() {
let width = NonZeroU32::new(100).unwrap();
let height = NonZeroU32::new(80).unwrap();
let buffer: Vec<u8> = (0..8000).map(|v| (v & 0xff) as u8).collect();
let src_image = Image::from_vec_u8(width, height, buffer, PixelType::U8).unwrap();
let mut dst_image = Image::new(width, height, PixelType::U8);
let mut resizer = Resizer::new(ResizeAlg::Convolution(FilterType::Lanczos3));
resizer
.resize(&src_image.view(), &mut dst_image.view_mut())
.unwrap();
assert!(matches!(
src_image.buffer().cmp(dst_image.buffer()),
Ordering::Equal
));
}
#[test]
fn resize_to_same_size_after_cropping() {
let width = NonZeroU32::new(100).unwrap();
let height = NonZeroU32::new(80).unwrap();
let src_width = NonZeroU32::new(120).unwrap();
let src_height = NonZeroU32::new(100).unwrap();
let buffer: Vec<u8> = (0..12000).map(|v| (v & 0xff) as u8).collect();
let src_image = Image::from_vec_u8(src_width, src_height, buffer, PixelType::U8).unwrap();
let mut src_view = src_image.view();
src_view
.set_crop_box(CropBox {
top: 10,
left: 10,
width,
height,
})
.unwrap();
let mut dst_image = Image::new(width, height, PixelType::U8);
let mut resizer = Resizer::new(ResizeAlg::Convolution(FilterType::Lanczos3));
resizer
.resize(&src_view, &mut dst_image.view_mut())
.unwrap();
let cropped_buffer: Vec<u8> = (0..12000u32)
.filter_map(|v| {
let row = v / 120;
let col = v % 120;
if (10..90u32).contains(&row) && (10..110u32).contains(&col) {
Some((v & 0xff) as u8)
} else {
None
}
})
.collect();
let dst_buffer = dst_image.into_vec();
assert!(matches!(cropped_buffer.cmp(&dst_buffer), Ordering::Equal));
}
fn downscale_test<P: PixelExt>(resize_alg: ResizeAlg, cpu_extensions: CpuExtensions) -> Vec<u8> {
let image = P::load_big_src_image();
assert_eq!(image.pixel_type(), P::pixel_type());