diff --git a/Cargo.lock b/Cargo.lock index 8465567..cd18709 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -198,15 +198,6 @@ 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" @@ -264,7 +255,7 @@ dependencies = [ "eyre", "fast_image_resize", "image", - "jpegxl-rs", + "jxl-oxide", "notify", "rand", "ron", @@ -359,12 +350,6 @@ 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" @@ -415,37 +400,6 @@ 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" @@ -729,16 +683,6 @@ 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" @@ -843,45 +787,153 @@ dependencies = [ ] [[package]] -name = "jpegxl-rs" -version = "0.11.1+libjxl-0.11.0" +name = "js-sys" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d991205c4cc682cbc5081b8cd39ff3c5e314c83030463e55b4827bdfec73beed" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ - "byteorder", - "derive_builder", - "half", - "image", - "jpegxl-sys", - "thiserror", + "wasm-bindgen", ] [[package]] -name = "jpegxl-src" -version = "0.11.1" +name = "jxl-bitstream" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68406840c4f428f87afdee1d62cfecf2abb064291c0b1a24fc95e91c61e5b4ff" +checksum = "5855ff16398ffbcf81fee52c41ca65326499c8764b21bb9952c367ace98995fb" dependencies = [ - "cmake", + "tracing", ] [[package]] -name = "jpegxl-sys" -version = "0.11.1+libjxl-0.11.0" +name = "jxl-coding" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c67c2a1feee51b3ae41700e12ef47b3ebf227f5dea2ae578b79d7fedfecb76f0" +checksum = "da5b5093904e940bc11ef50e872c7bdf7b6e88653f012b925f8479daf212b5c9" dependencies = [ - "jpegxl-src", - "pkg-config", + "jxl-bitstream", + "tracing", ] [[package]] -name = "js-sys" -version = "0.3.70" +name = "jxl-color" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "97f0dd548fabf9c094f9f2304059c86764f606b9040c0bfcfac55f155f423b55" dependencies = [ - "wasm-bindgen", + "jxl-bitstream", + "jxl-coding", + "jxl-grid", + "jxl-threadpool", + "tracing", +] + +[[package]] +name = "jxl-frame" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4719f285ebfff5e64f352d0ef149a5244aef4f8e6b5aa666ba6241e90b50632f" +dependencies = [ + "jxl-bitstream", + "jxl-coding", + "jxl-grid", + "jxl-image", + "jxl-modular", + "jxl-threadpool", + "jxl-vardct", + "tracing", +] + +[[package]] +name = "jxl-grid" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e941628e8de1dc6ba1d2bba8ebc68a69f8ff50cc7ddce5bc821658d1f4ea6e59" +dependencies = [ + "tracing", +] + +[[package]] +name = "jxl-image" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3824c81613c05c19a9e4329d569145d3f460c0fcadb3965bd8418162d43f7f4" +dependencies = [ + "jxl-bitstream", + "jxl-color", + "jxl-grid", + "tracing", +] + +[[package]] +name = "jxl-modular" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f48a5d003627f380004c29d35e51672da06ae343a2e6fe8d9c84295b9a3e843" +dependencies = [ + "jxl-bitstream", + "jxl-coding", + "jxl-grid", + "jxl-threadpool", + "tracing", +] + +[[package]] +name = "jxl-oxide" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c209f66ef0fe72df77b44ee6aae98eb87bc2dd236d6981e44e143cc37f33f6e" +dependencies = [ + "jxl-bitstream", + "jxl-color", + "jxl-frame", + "jxl-grid", + "jxl-image", + "jxl-render", + "jxl-threadpool", + "tracing", +] + +[[package]] +name = "jxl-render" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aec53c004c9171e89f15ad1f029d6b638cbd70d3a70276746bb8c75f9393bb64" +dependencies = [ + "jxl-bitstream", + "jxl-coding", + "jxl-color", + "jxl-frame", + "jxl-grid", + "jxl-image", + "jxl-modular", + "jxl-threadpool", + "jxl-vardct", + "tracing", +] + +[[package]] +name = "jxl-threadpool" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d2860c68899a3c6266044fc26c6a0041e9f27145f58cc69b6eedc1b77f5ee13" +dependencies = [ + "rayon", + "rayon-core", + "tracing", +] + +[[package]] +name = "jxl-vardct" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15da4b49b832b3d8a67329f47e2a1732e0847667938bb9b4a37d99a4668775c2" +dependencies = [ + "jxl-bitstream", + "jxl-coding", + "jxl-grid", + "jxl-modular", + "jxl-threadpool", + "tracing", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 082b0f1..d95cc19 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,9 +3,6 @@ name = "cosmic-bg" version = "0.1.0" edition = "2021" -[features] -vendored-jpegxl = ["jpegxl-rs/vendored"] - [dependencies] color-eyre = "0.6.3" colorgrad = { workspace = true } @@ -14,7 +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 = "0.11.1" +jxl-oxide = "0.9.0" notify = "6.1.1" rand = "0.8" ron = { workspace = true } diff --git a/debian/rules b/debian/rules index 15826e9..aa7592e 100755 --- a/debian/rules +++ b/debian/rules @@ -20,7 +20,7 @@ override_dh_auto_clean: fi override_dh_auto_build: - just build-vendored --features vendored-jpegxl + just build-vendored override_dh_install: just rootdir=$(DESTDIR) install diff --git a/src/wallpaper.rs b/src/wallpaper.rs index 13be871..f4876f9 100644 --- a/src/wallpaper.rs +++ b/src/wallpaper.rs @@ -11,7 +11,9 @@ use std::{ use cosmic_bg_config::{state::State, Color, Entry, SamplingMethod, ScalingMode, Source}; use cosmic_config::CosmicConfigEntry; -use image::{DynamicImage, ImageReader}; +use eyre::{eyre, OptionExt}; +use image::{DynamicImage, GrayAlphaImage, GrayImage, ImageReader, RgbImage, RgbaImage}; +use jxl_oxide::{EnumColourEncoding, JxlImage, PixelFormat}; use notify::{RecommendedWatcher, RecursiveMode, Watcher}; use rand::{seq::SliceRandom, thread_rng}; use sctk::reexports::{ @@ -389,35 +391,88 @@ fn current_image(output: &str) -> Option { wallpaper.map(|(_name, path)| path) } -/// Decodes JPEG XL image files into `image::DynamicImage` via `jpegxl-rs`. +/// Decodes JPEG XL image files into `image::DynamicImage` via `jxl-oxide`. 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 mut image = JxlImage::builder() + .open(path) + .expect("Failed to read image header"); + image.request_color_encoding(EnumColourEncoding::srgb( + jxl_oxide::RenderingIntent::Relative, + )); + let render = image.render_frame(0).map_err(|e| eyre!("{e}")); + let result: Option = match render { + Ok(render) => { + let framebuffer = render.image_all_channels(); + let output = match image.pixel_format() { + PixelFormat::Graya => GrayAlphaImage::from_raw( + framebuffer.width() as u32, + framebuffer.height() as u32, + framebuffer + .buf() + .iter() + .map(|x| x * 255. + 0.5) + .map(|x| x as u8) + .collect::>(), + ) + .map(DynamicImage::ImageLumaA8) + .ok_or_eyre("Can't decode gray alpha buffer"), + PixelFormat::Gray => GrayImage::from_raw( + framebuffer.width() as u32, + framebuffer.height() as u32, + framebuffer + .buf() + .iter() + .map(|x| x * 255. + 0.5) + .map(|x| x as u8) + .collect::>(), + ) + .map(DynamicImage::ImageLuma8) + .ok_or_eyre("Can't decode gray buffer"), + PixelFormat::Rgba => RgbaImage::from_raw( + framebuffer.width() as u32, + framebuffer.height() as u32, + framebuffer + .buf() + .iter() + .map(|x| x * 255. + 0.5) + .map(|x| x as u8) + .collect::>(), + ) + .map(DynamicImage::ImageRgba8) + .ok_or_eyre("Can't decode rgba buffer"), + PixelFormat::Rgb => RgbImage::from_raw( + framebuffer.width() as u32, + framebuffer.height() as u32, + framebuffer + .buf() + .iter() + .map(|x| x * 255. + 0.5) + .map(|x| x as u8) + .collect::>(), + ) + .map(DynamicImage::ImageRgb8) + .ok_or_eyre("Can't decode rgb buffer"), + //TODO: handle this + PixelFormat::Cmyk => return None, + PixelFormat::Cmyka => 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 + match output { + Ok(image) => Some(image), + Err(why) => { + tracing::warn!( + ?why, + "could not decode image pixel format: {}", + path.display() + ); + None + } + } } Err(why) => { tracing::warn!(?why, "could not decode image: {}", path.display()); None } - } + }; + result }