diff --git a/Cargo.lock b/Cargo.lock index c821131..8465567 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -198,6 +198,15 @@ dependencies = [ "x11rb", ] +[[package]] +name = "cmake" +version = "0.1.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb1e43aa7fd152b1f968787f7dbcdeb306d1867ff373c69955211876c053f91a" +dependencies = [ + "cc", +] + [[package]] name = "color-eyre" version = "0.6.3" @@ -255,6 +264,7 @@ dependencies = [ "eyre", "fast_image_resize", "image", + "jpegxl-rs", "notify", "rand", "ron", @@ -349,6 +359,12 @@ version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "csscolorparser" version = "0.6.2" @@ -399,6 +415,37 @@ dependencies = [ "syn 2.0.75", ] +[[package]] +name = "derive_builder" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.75", +] + +[[package]] +name = "derive_builder_macro" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" +dependencies = [ + "derive_builder_core", + "syn 2.0.75", +] + [[package]] name = "derive_setters" version = "0.1.6" @@ -682,6 +729,16 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + [[package]] name = "hermit-abi" version = "0.4.0" @@ -785,6 +842,39 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "jpegxl-rs" +version = "0.11.1+libjxl-0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d991205c4cc682cbc5081b8cd39ff3c5e314c83030463e55b4827bdfec73beed" +dependencies = [ + "byteorder", + "derive_builder", + "half", + "image", + "jpegxl-sys", + "thiserror", +] + +[[package]] +name = "jpegxl-src" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68406840c4f428f87afdee1d62cfecf2abb064291c0b1a24fc95e91c61e5b4ff" +dependencies = [ + "cmake", +] + +[[package]] +name = "jpegxl-sys" +version = "0.11.1+libjxl-0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c67c2a1feee51b3ae41700e12ef47b3ebf227f5dea2ae578b79d7fedfecb76f0" +dependencies = [ + "jpegxl-src", + "pkg-config", +] + [[package]] name = "js-sys" version = "0.3.70" @@ -1137,9 +1227,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "png" @@ -1501,18 +1591,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 7ced179..4110acb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ dirs = "5.0.1" eyre = "0.6.12" fast_image_resize = { version = "4.2.1", features = ["image"] } image = { workspace = true, features = ["hdr", "jpeg", "png", "rayon", "webp"] } +jpegxl-rs = { version = "0.11.1", features = ["vendored"] } notify = "6.1.1" rand = "0.8" ron = { workspace = true } diff --git a/src/wallpaper.rs b/src/wallpaper.rs index 2460981..13be871 100644 --- a/src/wallpaper.rs +++ b/src/wallpaper.rs @@ -123,27 +123,35 @@ impl Wallpaper { tracing::info!("No source for wallpaper"); continue; }; + cur_resized_img = match source { Source::Path(ref path) => { if self.current_image.is_none() { - self.current_image = Some(match ImageReader::open(&path) { - Ok(img) => { - match img - .with_guessed_format() - .ok() - .and_then(|f| f.decode().ok()) - { - Some(img) => img, - None => { - tracing::warn!( - "Could not decode image: {}", - path.display() - ); - continue; + self.current_image = Some(match path.extension() { + Some(ext) if ext == "jxl" => match decode_jpegxl(&path) { + Some(image) => image, + None => continue, + }, + + _ => match ImageReader::open(&path) { + Ok(img) => { + match img + .with_guessed_format() + .ok() + .and_then(|f| f.decode().ok()) + { + Some(img) => img, + None => { + tracing::warn!( + "could not decode image: {}", + path.display() + ); + continue; + } } } - } - Err(_) => continue, + Err(_) => continue, + }, }); } let img = self.current_image.as_ref().unwrap(); @@ -380,3 +388,36 @@ fn current_image(output: &str) -> Option { wallpaper.map(|(_name, path)| path) } + +/// Decodes JPEG XL image files into `image::DynamicImage` via `jpegxl-rs`. +fn decode_jpegxl(path: &std::path::Path) -> Option { + use jpegxl_rs::image::ToDynamic; + + let jxl_file = match std::fs::read(path) { + Ok(file) => file, + Err(why) => { + tracing::warn!(?why, "could not read image: {}", path.display()); + return None; + } + }; + + let jxl_decode_result = jpegxl_rs::decoder_builder() + .parallel_runner(&jpegxl_rs::ThreadsRunner::default()) + .build() + .and_then(move |decoder| decoder.decode_to_image(&jxl_file)); + + match jxl_decode_result { + Ok(Some(image)) => Some(image), + Ok(None) => { + tracing::warn!( + "decoded image could not be represented as a DynamicImage: {}", + path.display() + ); + None + } + Err(why) => { + tracing::warn!(?why, "could not decode image: {}", path.display()); + None + } + } +}