diff --git a/Cargo.lock b/Cargo.lock index 9f04b40..0c6791e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -422,31 +422,6 @@ dependencies = [ "piper", ] -[[package]] -name = "bon" -version = "3.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a602c73c7b0148ec6d12af6fd5cc7a46e2eacc8878271a999abac56eed12f561" -dependencies = [ - "bon-macros", - "rustversion", -] - -[[package]] -name = "bon-macros" -version = "3.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dee98b0db6a962de883bf5d20362dee4d7ca0d12fe39a7c6c73c844e1cd7c1f" -dependencies = [ - "darling", - "ident_case", - "prettyplease", - "proc-macro2", - "quote", - "rustversion", - "syn", -] - [[package]] name = "built" version = "0.8.1" @@ -479,12 +454,6 @@ dependencies = [ "syn", ] -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - [[package]] name = "byteorder-lite" version = "0.1.0" @@ -809,40 +778,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f" -[[package]] -name = "darling" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" -dependencies = [ - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn", -] - -[[package]] -name = "darling_macro" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" -dependencies = [ - "darling_core", - "quote", - "syn", -] - [[package]] name = "dirs" version = "6.0.0" @@ -1673,12 +1608,6 @@ dependencies = [ "winit", ] -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - [[package]] name = "image" version = "0.25.10" @@ -1720,7 +1649,6 @@ dependencies = [ "dirs", "iced", "image", - "jpegxl-rs", "rfd", ] @@ -1828,29 +1756,6 @@ dependencies = [ "libc", ] -[[package]] -name = "jpegxl-rs" -version = "0.14.0+libjxl-0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7d16fe73fb6d2e16b986392b716409c6ae6fabd35769d66bea391b016cdbc9" -dependencies = [ - "bon", - "byteorder", - "half", - "image", - "jpegxl-sys", - "thiserror 2.0.18", -] - -[[package]] -name = "jpegxl-sys" -version = "0.12.1+libjxl-0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00cb4f7ffb45ee4327e9ec6ca1a732f3abef470ee008f7d4be3afb414075cd7d" -dependencies = [ - "pkg-config", -] - [[package]] name = "js-sys" version = "0.3.103" @@ -2853,16 +2758,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn", -] - [[package]] name = "proc-macro-crate" version = "3.5.0" @@ -3530,12 +3425,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - [[package]] name = "svg_fmt" version = "0.4.5" diff --git a/Cargo.toml b/Cargo.toml index 5951fbc..668d6f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,4 +8,3 @@ iced = { version = "0.14.0", features = [ "image" ] } dirs = "6.0.0" image = "0.25.10" rfd = "0.17.2" -jpegxl-rs = "0.14.0" diff --git a/flake.nix b/flake.nix index 8f401aa..b86a384 100644 --- a/flake.nix +++ b/flake.nix @@ -36,10 +36,8 @@ commonArgs = { # all that's needed for artifacts and checks nativeBuildInputs = with pkgs; [ - pkg-config ]; buildInputs = with pkgs; [ - libjxl ]; src = ./.; @@ -66,7 +64,6 @@ "image/gif" "image/webp" "image/avif" - "image/jxl" "image/tiff" "image/bmp" "image/vnd.microsoft.icon" # .ico diff --git a/src/main.rs b/src/main.rs index e7bbd11..663d849 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,11 @@ -use std::{env, ffi::OsStr, fs, io::Write, path::Path}; +use std::{env, ffi::OsStr, fs}; use iced::{ Alignment, Color, Element, Length, Renderer, Subscription, Task, Theme, color, event, keyboard::{self, Key, key}, theme, widget, window, }; -use image::{DynamicImage, EncodableLayout, ImageDecoder, ImageReader, RgbaImage, imageops}; -use jpegxl_rs::image::ToDynamic; +use image::{EncodableLayout, ImageReader, RgbaImage, codecs::webp::WebPEncoder, imageops}; use rfd::FileDialog; #[derive(Clone, Debug)] @@ -16,7 +15,7 @@ enum Message { Event(iced::Event), } -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] struct State { image: Option, image_display: Option, @@ -25,9 +24,20 @@ struct State { } impl State { fn new() -> (Self, Task) { - let mut state = State::default(); + let state = State { + image_display: None, + image: env::args().nth(1).and_then(|path| { + Some( + ImageReader::open(path) + .unwrap() + .decode() + .unwrap() + .into_rgba8(), + ) + }), - state.error = env::args().nth(1).and_then(|path| state.load_image(path)); + error: None, + }; let allocate_image = state.allocate_image(); (state, allocate_image) @@ -114,92 +124,13 @@ impl State { Task::none() } - fn load_image(&mut self, path: impl AsRef) -> Option { - let path = path.as_ref(); - - let decoded_image = match path.extension().map(OsStr::to_string_lossy).as_deref() { - Some("jxl") => { - let data = match std::fs::read(path) { - Ok(d) => d, - Err(e) => { - return Some(format!( - "failed to read data from '{}': {e}", - path.display() - )); - } - }; - - match jpegxl_rs::decoder_builder() - .build() - .unwrap() - .decode_to_image(&data) - { - Ok(Some(decoded_image)) => decoded_image, - Ok(None) => { - return Some(format!( - "failed to convert jxl '{}' to DynamicImage", - path.display() - )); - } - Err(e) => return Some(format!("faled to decode '{}' {e}", path.display())), - } - } - - _ => { - let reader = match ImageReader::open(&path) { - Ok(r) => r, - Err(e) => { - return Some(format!( - "failed to create reader for '{}': {e}", - path.display() - )); - } - }; - - let mut decoder = match reader.into_decoder() { - Ok(d) => d, - Err(e) => { - return Some(format!( - "failed to create decoder for '{}': {e}", - path.display() - )); - } - }; - - let oreintation = match decoder.orientation() { - Ok(o) => o, - Err(e) => { - return Some(format!( - "failed to get oreintation of '{}': {e}", - path.display() - )); - } - }; - - let mut decoded_image = match DynamicImage::from_decoder(decoder) { - Ok(i) => i, - Err(e) => { - return Some(format!("failed to decode image '{}': {e}", path.display())); - } - }; - - decoded_image.apply_orientation(oreintation); - - decoded_image - } - }; - - self.image = Some(decoded_image.into_rgba8()); - - None - } fn open_image(&mut self) -> Option { let Some(path) = FileDialog::new() .add_filter( "image", &[ - "png", "PNG", "jpg", "JPG", "jpeg", "JPEG", "avif", "jxl", "bmp", "exr", "ff", - "gif", "hdr", "ico", "pnm", "qoi", "tga", "tiff", "webp", + "png", "PNG", "jpg", "JPG", "jpeg", "JPEG", "avif", "bmp", "exr", "ff", "gif", + "hdr", "ico", "pnm", "qoi", "tga", "tiff", "webp", ], ) .pick_file() @@ -207,7 +138,19 @@ impl State { return Some("no path to open provided".into()); }; - self.load_image(path) + let reader = match ImageReader::open(path) { + Ok(r) => r, + Err(e) => return Some(format!("failed to create reader: {e}")), + }; + + let decoded_image = match reader.decode() { + Ok(i) => i, + Err(e) => return Some(format!("failed to decode image: {e}")), + }; + + self.image = Some(decoded_image.into_rgba8()); + + None } fn save_image(&self) -> Option { @@ -219,38 +162,24 @@ impl State { return Some("no path to save provided".into()); }; - let mut file = match fs::File::create(&path) { - Ok(f) => f, - Err(e) => return Some(format!("failed to create file '{}': {e}", path.display())), - }; + match fs::File::create(&path) { + Err(e) => return Some(format!("failed to create file: {e}")), + Ok(file) => { + let maybe_encoder = match path.extension().map(OsStr::to_string_lossy).as_deref() { + Some("webp") => Some(WebPEncoder::new_lossless(file)), - match path.extension().map(OsStr::to_string_lossy).as_deref() { - Some("jxl") => { - let mut encoder = jpegxl_rs::encoder_builder() - .speed(jpegxl_rs::encode::EncoderSpeed::Glacier) - .lossless(true) - .build() - .unwrap(); - let rgb_image = DynamicImage::from(image.to_owned()).into_rgb8(); - let jxl = match encoder.encode::( - &rgb_image, - rgb_image.width(), - rgb_image.height(), - ) { - Ok(j) => j, - Err(e) => { - return Some(format!("failed to encode jxl '{}': {e}", path.display())); - } + None | Some(_) => None, }; - if let Err(e) = file.write(&jxl.data) { - return Some(format!("failed to write jxl to '{}': {e}", path.display())); - }; - } - _ => { - if let Err(e) = image.save(&path) { - return Some(format!("failed to save '{}': {e}", path.display())); + let result = if let Some(encoder) = maybe_encoder { + image.write_with_encoder(encoder) + } else { + image.save(path) }; + + if let Err(e) = result { + return Some(format!("failed to save image: {e}")); + } } };