Merge images support

Thanks to Ken Sedgwick for getting this over the line by generalizing
our images cache!

Ken Sedgwick (2):
      build: updated num_enum to get around build problem
      Extend ImageCache to handle content images

William Casarin (4):
      update image to 0.25
      initial image support
      use slightly better carousel id

Fixes: https://github.com/damus-io/notedeck/issues/249
Fixes: https://github.com/damus-io/notedeck/issues/148
This commit is contained in:
William Casarin 2024-09-02 17:56:18 -07:00
commit 6a989e388b
7 changed files with 529 additions and 103 deletions

421
Cargo.lock generated
View File

@ -76,6 +76,12 @@ dependencies = [
"memchr",
]
[[package]]
name = "aligned-vec"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1"
[[package]]
name = "allocator-api2"
version = "0.2.18"
@ -117,7 +123,7 @@ dependencies = [
"ndk 0.8.0",
"ndk-context",
"ndk-sys 0.5.0+25.2.9519653",
"num_enum 0.7.2",
"num_enum 0.7.3",
"thiserror",
]
@ -209,6 +215,12 @@ version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
[[package]]
name = "arbitrary"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110"
[[package]]
name = "arboard"
version = "3.4.0"
@ -224,6 +236,17 @@ dependencies = [
"x11rb",
]
[[package]]
name = "arg_enum_proc_macro"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.68",
]
[[package]]
name = "arrayref"
version = "0.3.7"
@ -285,6 +308,29 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
[[package]]
name = "av1-grain"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6678909d8c5d46a42abcf571271e15fdbc0a225e3646cf23762cd415046c78bf"
dependencies = [
"anyhow",
"arrayvec",
"log",
"nom",
"num-rational",
"v_frame",
]
[[package]]
name = "avif-serialize"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "876c75a42f6364451a033496a14c44bffe41f5f4a8236f697391f11024e596d2"
dependencies = [
"arrayvec",
]
[[package]]
name = "backtrace"
version = "0.3.73"
@ -453,6 +499,12 @@ version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]]
name = "bitstream-io"
version = "2.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "415f8399438eb5e4b2f73ed3152a3448b98149dda642a957ee704e1daa5cf1d8"
[[package]]
name = "block"
version = "0.1.6"
@ -505,6 +557,12 @@ dependencies = [
"objc2 0.5.2",
]
[[package]]
name = "built"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6a6c0b39c38fd754ac338b00a88066436389c0f029da5d37d1e01091d9b7c17"
[[package]]
name = "bumpalo"
version = "3.16.0"
@ -537,6 +595,12 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "byteorder-lite"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
[[package]]
name = "bytes"
version = "1.6.0"
@ -604,6 +668,16 @@ dependencies = [
"nom",
]
[[package]]
name = "cfg-expr"
version = "0.15.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02"
dependencies = [
"smallvec",
"target-lexicon",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
@ -936,7 +1010,7 @@ dependencies = [
"egui-wgpu",
"egui-winit",
"egui_glow",
"image 0.25.1",
"image",
"js-sys",
"log",
"objc2 0.5.2",
@ -1015,7 +1089,7 @@ dependencies = [
"egui",
"ehttp 0.5.0",
"enum-map",
"image 0.25.1",
"image",
"log",
"mime_guess2",
"resvg",
@ -1797,24 +1871,6 @@ dependencies = [
"unicode-normalization",
]
[[package]]
name = "image"
version = "0.24.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d"
dependencies = [
"bytemuck",
"byteorder",
"color_quant",
"exr",
"gif",
"jpeg-decoder",
"num-traits",
"png",
"qoi",
"tiff",
]
[[package]]
name = "image"
version = "0.25.1"
@ -1824,9 +1880,28 @@ dependencies = [
"bytemuck",
"byteorder",
"color_quant",
"exr",
"gif",
"image-webp",
"num-traits",
"png",
"qoi",
"ravif",
"rayon",
"rgb",
"tiff",
"zune-core",
"zune-jpeg",
]
[[package]]
name = "image-webp"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d730b085583c4d789dfd07fdcf185be59501666a90c97c40162b37e4fdad272d"
dependencies = [
"byteorder-lite",
"thiserror",
]
[[package]]
@ -1835,6 +1910,12 @@ version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "029d73f573d8e8d63e6d5020011d3255b28c3ba85d6cf870a07184ed23de9284"
[[package]]
name = "imgref"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44feda355f4159a7c757171a77de25daf6411e217b4cabd03bd6650690468126"
[[package]]
name = "indexmap"
version = "2.2.6"
@ -1868,6 +1949,17 @@ dependencies = [
"web-sys",
]
[[package]]
name = "interpolate_name"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.68",
]
[[package]]
name = "ipnet"
version = "2.9.0"
@ -1942,9 +2034,6 @@ name = "jpeg-decoder"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0"
dependencies = [
"rayon",
]
[[package]]
name = "js-sys"
@ -2005,6 +2094,17 @@ version = "0.2.155"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
name = "libfuzzer-sys"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7"
dependencies = [
"arbitrary",
"cc",
"once_cell",
]
[[package]]
name = "libloading"
version = "0.7.4"
@ -2064,6 +2164,15 @@ version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "loop9"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062"
dependencies = [
"imgref",
]
[[package]]
name = "lz4_flex"
version = "0.11.3"
@ -2079,6 +2188,16 @@ dependencies = [
"libc",
]
[[package]]
name = "maybe-rayon"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519"
dependencies = [
"cfg-if",
"rayon",
]
[[package]]
name = "memchr"
version = "2.7.4"
@ -2212,7 +2331,7 @@ dependencies = [
"jni-sys",
"log",
"ndk-sys 0.5.0+25.2.9519653",
"num_enum 0.7.2",
"num_enum 0.7.3",
"raw-window-handle 0.6.2",
"thiserror",
]
@ -2247,6 +2366,12 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e664971378a3987224f7a0e10059782035e89899ae403718ee07de85bec42afe"
[[package]]
name = "new_debug_unreachable"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
[[package]]
name = "nohash-hasher"
version = "0.2.0"
@ -2263,6 +2388,12 @@ dependencies = [
"minimal-lexical",
]
[[package]]
name = "noop_proc_macro"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8"
[[package]]
name = "nostr"
version = "0.30.0"
@ -2326,7 +2457,7 @@ dependencies = [
"enostr",
"env_logger 0.10.2",
"hex",
"image 0.24.9",
"image",
"log",
"nostrdb",
"poll-promise",
@ -2358,12 +2489,53 @@ dependencies = [
"winapi",
]
[[package]]
name = "num-bigint"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
dependencies = [
"num-integer",
"num-traits",
]
[[package]]
name = "num-conv"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]]
name = "num-derive"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.68",
]
[[package]]
name = "num-integer"
version = "0.1.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
dependencies = [
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
dependencies = [
"num-bigint",
"num-integer",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.19"
@ -2403,11 +2575,11 @@ dependencies = [
[[package]]
name = "num_enum"
version = "0.7.2"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845"
checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179"
dependencies = [
"num_enum_derive 0.7.2",
"num_enum_derive 0.7.3",
]
[[package]]
@ -2416,7 +2588,7 @@ version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799"
dependencies = [
"proc-macro-crate 1.3.1",
"proc-macro-crate",
"proc-macro2",
"quote",
"syn 1.0.109",
@ -2428,7 +2600,7 @@ version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6"
dependencies = [
"proc-macro-crate 1.3.1",
"proc-macro-crate",
"proc-macro2",
"quote",
"syn 2.0.68",
@ -2436,11 +2608,11 @@ dependencies = [
[[package]]
name = "num_enum_derive"
version = "0.7.2"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b"
checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56"
dependencies = [
"proc-macro-crate 3.1.0",
"proc-macro-crate",
"proc-macro2",
"quote",
"syn 2.0.68",
@ -2815,15 +2987,6 @@ dependencies = [
"toml_edit 0.19.15",
]
[[package]]
name = "proc-macro-crate"
version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284"
dependencies = [
"toml_edit 0.21.1",
]
[[package]]
name = "proc-macro2"
version = "1.0.86"
@ -2838,6 +3001,19 @@ name = "profiling"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58"
dependencies = [
"profiling-procmacros",
]
[[package]]
name = "profiling-procmacros"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8021cf59c8ec9c432cfc2526ac6b8aa508ecaf29cd415f271b8406c1b851c3fd"
dependencies = [
"quote",
"syn 2.0.68",
]
[[package]]
name = "puffin"
@ -2881,6 +3057,12 @@ dependencies = [
"bytemuck",
]
[[package]]
name = "quick-error"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
[[package]]
name = "quick-xml"
version = "0.31.0"
@ -2976,6 +3158,56 @@ dependencies = [
"getrandom",
]
[[package]]
name = "rav1e"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9"
dependencies = [
"arbitrary",
"arg_enum_proc_macro",
"arrayvec",
"av1-grain",
"bitstream-io",
"built",
"cfg-if",
"interpolate_name",
"itertools",
"libc",
"libfuzzer-sys",
"log",
"maybe-rayon",
"new_debug_unreachable",
"noop_proc_macro",
"num-derive",
"num-traits",
"once_cell",
"paste",
"profiling",
"rand",
"rand_chacha",
"simd_helpers",
"system-deps",
"thiserror",
"v_frame",
"wasm-bindgen",
]
[[package]]
name = "ravif"
version = "0.11.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67376f469e7e7840d0040bbf4b9b3334005bb167f814621326e4c7ab8cd6e944"
dependencies = [
"avif-serialize",
"imgref",
"loop9",
"quick-error",
"rav1e",
"rayon",
"rgb",
]
[[package]]
name = "raw-window-handle"
version = "0.5.2"
@ -3461,6 +3693,15 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_spanned"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0"
dependencies = [
"serde",
]
[[package]]
name = "serde_urlencoded"
version = "0.7.1"
@ -3516,6 +3757,15 @@ version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
[[package]]
name = "simd_helpers"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6"
dependencies = [
"quote",
]
[[package]]
name = "simplecss"
version = "0.2.1"
@ -3712,6 +3962,25 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
[[package]]
name = "system-deps"
version = "6.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349"
dependencies = [
"cfg-expr",
"heck",
"pkg-config",
"toml",
"version-compare",
]
[[package]]
name = "target-lexicon"
version = "0.12.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f"
[[package]]
name = "termcolor"
version = "1.4.1"
@ -3912,11 +4181,26 @@ dependencies = [
"webpki-roots 0.22.6",
]
[[package]]
name = "toml"
version = "0.8.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"toml_edit 0.22.14",
]
[[package]]
name = "toml_datetime"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
@ -3926,18 +4210,20 @@ checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
dependencies = [
"indexmap",
"toml_datetime",
"winnow",
"winnow 0.5.40",
]
[[package]]
name = "toml_edit"
version = "0.21.1"
version = "0.22.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1"
checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38"
dependencies = [
"indexmap",
"serde",
"serde_spanned",
"toml_datetime",
"winnow",
"winnow 0.6.13",
]
[[package]]
@ -4247,6 +4533,17 @@ dependencies = [
"getrandom",
]
[[package]]
name = "v_frame"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6f32aaa24bacd11e488aa9ba66369c7cd514885742c9fe08cfe85884db3e92b"
dependencies = [
"aligned-vec",
"num-traits",
"wasm-bindgen",
]
[[package]]
name = "valuable"
version = "0.1.0"
@ -4259,6 +4556,12 @@ version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eab68b56840f69efb0fefbe3ab6661499217ffdc58e2eef7c3f6f69835386322"
[[package]]
name = "version-compare"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b"
[[package]]
name = "version_check"
version = "0.9.4"
@ -4983,6 +5286,15 @@ dependencies = [
"memchr",
]
[[package]]
name = "winnow"
version = "0.6.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1"
dependencies = [
"memchr",
]
[[package]]
name = "winreg"
version = "0.52.0"
@ -5088,6 +5400,12 @@ version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
[[package]]
name = "zune-core"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a"
[[package]]
name = "zune-inflate"
version = "0.2.54"
@ -5096,3 +5414,12 @@ checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02"
dependencies = [
"simd-adler32",
]
[[package]]
name = "zune-jpeg"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec866b44a2a1fd6133d363f073ca1b179f438f99e7e5bfb1e33f7181facfe448"
dependencies = [
"zune-core",
]

View File

@ -21,7 +21,7 @@ egui_tabs = { git = "https://github.com/damus-io/egui-tabs", branch = "egui-0.28
egui_nav = { git = "https://github.com/damus-io/egui-nav", branch = "egui-0.28" }
egui_virtual_list = { git = "https://github.com/jb55/hello_egui", branch = "egui-0.28", package = "egui_virtual_list" }
reqwest = { version = "0.12.4", default-features = false, features = [ "rustls-tls-native-roots" ] }
image = { version = "0.24", features = ["jpeg", "png", "webp"] }
image = { version = "0.25", features = ["jpeg", "png", "webp"] }
log = "0.4.17"
poll-promise = { version = "0.3.0", features = ["tokio"] }
serde_derive = "1"

View File

@ -102,54 +102,72 @@ pub fn round_image(image: &mut ColorImage) {
}
}
fn process_pfp_bitmap(size: u32, image: &mut image::DynamicImage) -> ColorImage {
fn process_pfp_bitmap(imgtyp: ImageType, image: &mut image::DynamicImage) -> ColorImage {
#[cfg(feature = "profiling")]
puffin::profile_function!();
// Crop square
let smaller = image.width().min(image.height());
match imgtyp {
ImageType::Content(w, h) => {
let image = image.resize(w, h, FilterType::CatmullRom); // DynamicImage
let image_buffer = image.into_rgba8(); // RgbaImage (ImageBuffer)
let color_image = ColorImage::from_rgba_unmultiplied(
[
image_buffer.width() as usize,
image_buffer.height() as usize,
],
image_buffer.as_flat_samples().as_slice(),
);
color_image
}
ImageType::Profile(size) => {
// Crop square
let smaller = image.width().min(image.height());
if image.width() > smaller {
let excess = image.width() - smaller;
*image = image.crop_imm(excess / 2, 0, image.width() - excess, image.height());
} else if image.height() > smaller {
let excess = image.height() - smaller;
*image = image.crop_imm(0, excess / 2, image.width(), image.height() - excess);
if image.width() > smaller {
let excess = image.width() - smaller;
*image = image.crop_imm(excess / 2, 0, image.width() - excess, image.height());
} else if image.height() > smaller {
let excess = image.height() - smaller;
*image = image.crop_imm(0, excess / 2, image.width(), image.height() - excess);
}
let image = image.resize(size, size, FilterType::CatmullRom); // DynamicImage
let image_buffer = image.into_rgba8(); // RgbaImage (ImageBuffer)
let mut color_image = ColorImage::from_rgba_unmultiplied(
[
image_buffer.width() as usize,
image_buffer.height() as usize,
],
image_buffer.as_flat_samples().as_slice(),
);
round_image(&mut color_image);
color_image
}
}
let image = image.resize(size, size, FilterType::CatmullRom); // DynamicImage
let image_buffer = image.into_rgba8(); // RgbaImage (ImageBuffer)
let mut color_image = ColorImage::from_rgba_unmultiplied(
[
image_buffer.width() as usize,
image_buffer.height() as usize,
],
image_buffer.as_flat_samples().as_slice(),
);
round_image(&mut color_image);
color_image
}
fn parse_img_response(response: ehttp::Response, size: u32) -> Result<ColorImage> {
fn parse_img_response(response: ehttp::Response, imgtyp: ImageType) -> Result<ColorImage> {
#[cfg(feature = "profiling")]
puffin::profile_function!();
let content_type = response.content_type().unwrap_or_default();
let size_hint = match imgtyp {
ImageType::Profile(size) => SizeHint::Size(size, size),
ImageType::Content(w, h) => SizeHint::Size(w, h),
};
if content_type.starts_with("image/svg") {
#[cfg(feature = "profiling")]
puffin::profile_scope!("load_svg");
let mut color_image = egui_extras::image::load_svg_bytes_with_size(
&response.bytes,
Some(SizeHint::Size(size, size)),
)?;
let mut color_image =
egui_extras::image::load_svg_bytes_with_size(&response.bytes, Some(size_hint))?;
round_image(&mut color_image);
Ok(color_image)
} else if content_type.starts_with("image/") {
#[cfg(feature = "profiling")]
puffin::profile_scope!("load_from_memory");
let mut dyn_image = image::load_from_memory(&response.bytes)?;
Ok(process_pfp_bitmap(size, &mut dyn_image))
Ok(process_pfp_bitmap(imgtyp, &mut dyn_image))
} else {
Err(format!("Expected image, found content-type {:?}", content_type).into())
}
@ -181,11 +199,20 @@ fn fetch_img_from_disk(
})
}
/// Controls type-specific handling
#[derive(Debug, Clone, Copy)]
pub enum ImageType {
/// Profile Image (size)
Profile(u32),
/// Content Image (width, height)
Content(u32, u32),
}
pub fn fetch_img(
img_cache: &ImageCache,
ctx: &egui::Context,
url: &str,
size: u32,
imgtyp: ImageType,
) -> Promise<Result<TextureHandle>> {
let key = ImageCache::key(url);
let path = img_cache.cache_dir.join(key);
@ -193,7 +220,7 @@ pub fn fetch_img(
if path.exists() {
fetch_img_from_disk(ctx, url, &path)
} else {
fetch_img_from_net(&img_cache.cache_dir, ctx, url, size)
fetch_img_from_net(&img_cache.cache_dir, ctx, url, imgtyp)
}
// TODO: fetch image from local cache
@ -203,7 +230,7 @@ fn fetch_img_from_net(
cache_path: &path::Path,
ctx: &egui::Context,
url: &str,
size: u32,
imgtyp: ImageType,
) -> Promise<Result<TextureHandle>> {
let (sender, promise) = Promise::new();
let request = ehttp::Request::get(url);
@ -213,7 +240,7 @@ fn fetch_img_from_net(
ehttp::fetch(request, move |response| {
let handle = response
.map_err(Error::Generic)
.and_then(|resp| parse_img_response(resp, size))
.and_then(|resp| parse_img_response(resp, imgtyp))
.map(|img| {
let texture_handle = ctx.load_texture(&cloned_url, img.clone(), Default::default());

View File

@ -42,7 +42,7 @@ impl ImageCache {
data.as_raw(),
data.size[0] as u32,
data.size[1] as u32,
image::ColorType::Rgba8,
image::ColorType::Rgba8.into(),
)?;
Ok(())

View File

@ -202,6 +202,7 @@ impl TimelineTab {
let selection = 0i32;
let mut list = VirtualList::new();
list.hide_on_resize(None);
list.over_scan(1000.0);
let list = Rc::new(RefCell::new(list));
let notes: Vec<NoteRef> = Vec::with_capacity(cap);
@ -344,7 +345,6 @@ impl Timeline {
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum MergeKind {
FrontInsert,
Spliced,

View File

@ -1,4 +1,7 @@
use crate::images::ImageType;
use crate::imgcache::ImageCache;
use crate::ui::note::NoteOptions;
use crate::ui::ProfilePic;
use crate::{colors, ui, Damus};
use egui::{Color32, Hyperlink, Image, RichText};
use nostrdb::{BlockType, Mention, Note, NoteKey, Transaction};
@ -111,7 +114,7 @@ fn render_note_contents(
puffin::profile_function!();
let selectable = options.has_selectable_text();
let images: Vec<String> = vec![];
let mut images: Vec<String> = vec![];
let mut inline_note: Option<(&[u8; 32], &str)> = None;
let resp = ui.horizontal_wrapped(|ui| {
@ -156,19 +159,17 @@ fn render_note_contents(
}
BlockType::Url => {
/*
let url = block.as_str().to_lowercase();
if url.ends_with("png") || url.ends_with("jpg") {
images.push(url);
let lower_url = block.as_str().to_lowercase();
if lower_url.ends_with("png") || lower_url.ends_with("jpg") {
images.push(block.as_str().to_string());
} else {
*/
#[cfg(feature = "profiling")]
puffin::profile_scope!("url contents");
ui.add(Hyperlink::from_label_and_url(
RichText::new(block.as_str()).color(colors::PURPLE),
block.as_str(),
));
//}
#[cfg(feature = "profiling")]
puffin::profile_scope!("url contents");
ui.add(Hyperlink::from_label_and_url(
RichText::new(block.as_str()).color(colors::PURPLE),
block.as_str(),
));
}
}
BlockType::Text => {
@ -188,15 +189,85 @@ fn render_note_contents(
render_note_preview(ui, damus, txn, id, block_str);
}
for image in images {
let img_resp = ui.add(Image::new(image.clone()));
img_resp.context_menu(|ui| {
if ui.button("Copy Link").clicked() {
ui.ctx().copy_text(image);
ui.close_menu();
}
});
if !images.is_empty() && !damus.textmode {
ui.add_space(2.0);
let carousel_id = egui::Id::new(("carousel", note.key().expect("expected tx note")));
image_carousel(ui, &mut damus.img_cache, images, carousel_id);
ui.add_space(2.0);
}
resp
}
fn image_carousel(
ui: &mut egui::Ui,
img_cache: &mut ImageCache,
images: Vec<String>,
carousel_id: egui::Id,
) {
// let's make sure everything is within our area
let height = 360.0;
let width = ui.available_size().x;
let spinsz = if height > width { width } else { height };
ui.add_sized([width, height], |ui: &mut egui::Ui| {
egui::ScrollArea::horizontal()
.id_source(carousel_id)
.show(ui, |ui| {
ui.horizontal(|ui| {
for image in images {
// If the cache is empty, initiate the fetch
let m_cached_promise = img_cache.map().get(&image);
if m_cached_promise.is_none() {
let res = crate::images::fetch_img(
img_cache,
ui.ctx(),
&image,
ImageType::Content(width.round() as u32, height.round() as u32),
);
img_cache.map_mut().insert(image.to_owned(), res);
}
// What is the state of the fetch?
match img_cache.map()[&image].ready() {
// Still waiting
None => {
ui.add(egui::Spinner::new().size(spinsz));
}
// Failed to fetch image!
Some(Err(_err)) => {
// FIXME - use content-specific error instead
let no_pfp = crate::images::fetch_img(
img_cache,
ui.ctx(),
ProfilePic::no_pfp_url(),
ImageType::Profile(128),
);
img_cache.map_mut().insert(image.to_owned(), no_pfp);
// spin until next pass
ui.add(egui::Spinner::new().size(spinsz));
}
// Use the previously resolved image
Some(Ok(img)) => {
let img_resp = ui.add(
Image::new(img)
.max_height(height)
.rounding(5.0)
.fit_to_original_size(1.0),
);
img_resp.context_menu(|ui| {
if ui.button("Copy Link").clicked() {
ui.ctx().copy_text(image);
ui.close_menu();
}
});
}
}
}
})
.response
})
.inner
});
}

View File

@ -1,3 +1,4 @@
use crate::images::ImageType;
use crate::imgcache::ImageCache;
use crate::ui::{Preview, PreviewConfig, View};
use egui::{vec2, Sense, TextureHandle};
@ -72,7 +73,7 @@ fn render_pfp(
let m_cached_promise = img_cache.map().get(url);
if m_cached_promise.is_none() {
let res = crate::images::fetch_img(img_cache, ui.ctx(), url, img_size);
let res = crate::images::fetch_img(img_cache, ui.ctx(), url, ImageType::Profile(img_size));
img_cache.map_mut().insert(url.to_owned(), res);
}
@ -87,7 +88,7 @@ fn render_pfp(
img_cache,
ui.ctx(),
ProfilePic::no_pfp_url(),
img_size,
ImageType::Profile(img_size),
);
img_cache.map_mut().insert(url.to_owned(), no_pfp);
}