feat: start work on jxl support

This commit is contained in:
electria 2026-07-02 15:57:29 -07:00
commit 770bdc76d3
Signed by: electria
SSH key fingerprint: SHA256:8LlB3ucPbBHqozqkhsNbaV5oG3SlzzqUj8FZDL6IPQs
4 changed files with 135 additions and 22 deletions

View file

@ -1,4 +1,4 @@
use std::{env, ffi::OsStr, fs, path::Path};
use std::{env, ffi::OsStr, fs, io::Read, path::Path};
use iced::{
Alignment, Color, Element, Length, Renderer, Subscription, Task, Theme, color, event,
@ -6,9 +6,10 @@ use iced::{
theme, widget, window,
};
use image::{
DynamicImage, EncodableLayout, ImageDecoder, ImageReader, RgbaImage, codecs::webp::WebPEncoder,
imageops,
DynamicImage, EncodableLayout, ImageDecoder, ImageReader, RgbImage, RgbaImage,
codecs::webp::WebPEncoder, imageops,
};
use jpegxl_rs::decode::JxlDecoder;
use rfd::FileDialog;
#[derive(Clone, Debug)]
@ -168,8 +169,8 @@ impl State {
.add_filter(
"image",
&[
"png", "PNG", "jpg", "JPG", "jpeg", "JPEG", "avif", "bmp", "exr", "ff", "gif",
"hdr", "ico", "pnm", "qoi", "tga", "tiff", "webp",
"png", "PNG", "jpg", "JPG", "jpeg", "JPEG", "avif", "jxl", "bmp", "exr", "ff",
"gif", "hdr", "ico", "pnm", "qoi", "tga", "tiff", "webp",
],
)
.pick_file()
@ -189,24 +190,21 @@ impl State {
return Some("no path to save provided".into());
};
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)),
let mut file = match fs::File::create(&path) {
Ok(f) => f,
Err(e) => return Some(format!("failed to create file '{}': {e}", path.display())),
};
None | Some(_) => None,
};
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}"));
}
match path.extension().map(OsStr::to_string_lossy).as_deref() {
Some("jxl") => {
jpegxl_rs::encoder_builder().build().unwrap().encode(
RgbImage::from(DynamicImage::from(*image)).as_bytes(),
image.width(),
image.height(),
);
}
None | Some(_) => {
image.save(path);
}
};