feat: switch to pure-rust jxl decoder
this makes the logic drastically simpler; as it comes with image crate integration. however, images can no longer be saved as JXL with this version (as jxl-oxide is decoder-only)
This commit is contained in:
parent
89b4639a69
commit
5a83fe39e9
5 changed files with 238 additions and 201 deletions
|
|
@ -175,6 +175,8 @@ impl State {
|
|||
}
|
||||
|
||||
fn main() -> Result<(), iced::Error> {
|
||||
jxl_oxide::integration::register_image_decoding_hook();
|
||||
|
||||
iced::application(State::new, State::update, State::view)
|
||||
.subscription(State::subscription)
|
||||
.title(State::title)
|
||||
|
|
|
|||
147
src/utils.rs
147
src/utils.rs
|
|
@ -1,91 +1,50 @@
|
|||
use std::{
|
||||
ffi::OsStr,
|
||||
fs,
|
||||
io::Write,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use image::{DynamicImage, ImageDecoder, ImageReader, RgbaImage};
|
||||
use jpegxl_rs::image::ToDynamic;
|
||||
use rfd::FileDialog;
|
||||
|
||||
pub fn load_image(path: impl AsRef<Path>) -> Result<RgbaImage, String> {
|
||||
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 Err(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 Err(format!(
|
||||
"failed to convert jxl '{}' to DynamicImage",
|
||||
path.display()
|
||||
));
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(format!("failed to decode jxl '{}': {e}", path.display()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
let reader = match ImageReader::open(path) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Err(format!(
|
||||
"failed to create reader for '{}': {e}",
|
||||
path.display()
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let mut decoder = match reader.into_decoder() {
|
||||
Ok(d) => d,
|
||||
Err(e) => {
|
||||
return Err(format!(
|
||||
"failed to create decoder for '{}': {e}",
|
||||
path.display()
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let oreintation = match decoder.orientation() {
|
||||
Ok(o) => o,
|
||||
Err(e) => {
|
||||
return Err(format!(
|
||||
"failed to get oreintation of '{}': {e}",
|
||||
path.display()
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let mut decoded_image = match DynamicImage::from_decoder(decoder) {
|
||||
Ok(i) => i,
|
||||
Err(e) => {
|
||||
return Err(format!("failed to decode image '{}': {e}", path.display()));
|
||||
}
|
||||
};
|
||||
|
||||
decoded_image.apply_orientation(oreintation);
|
||||
|
||||
decoded_image
|
||||
let reader = match ImageReader::open(path) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Err(format!(
|
||||
"failed to create reader for '{}': {e}",
|
||||
path.display()
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let mut decoder = match reader.into_decoder() {
|
||||
Ok(d) => d,
|
||||
Err(e) => {
|
||||
return Err(format!(
|
||||
"failed to create decoder for '{}': {e}",
|
||||
path.display()
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let oreintation = match decoder.orientation() {
|
||||
Ok(o) => o,
|
||||
Err(e) => {
|
||||
return Err(format!(
|
||||
"failed to get oreintation of '{}': {e}",
|
||||
path.display()
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let mut decoded_image = match DynamicImage::from_decoder(decoder) {
|
||||
Ok(i) => i,
|
||||
Err(e) => {
|
||||
return Err(format!("failed to decode image '{}': {e}", path.display()));
|
||||
}
|
||||
};
|
||||
|
||||
decoded_image.apply_orientation(oreintation);
|
||||
|
||||
Ok(decoded_image.into_rgba8())
|
||||
}
|
||||
pub fn pick_image() -> Result<PathBuf, String> {
|
||||
|
|
@ -114,36 +73,8 @@ pub fn save_image(image: Option<&RgbaImage>) -> Result<(), String> {
|
|||
return Err("no path to save provided".into());
|
||||
};
|
||||
|
||||
let mut file = match fs::File::create(&path) {
|
||||
Ok(f) => f,
|
||||
Err(e) => return Err(format!("failed to create file '{}': {e}", path.display())),
|
||||
};
|
||||
|
||||
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::<u8, u8>(&rgb_image, rgb_image.width(), rgb_image.height()) {
|
||||
Ok(j) => j,
|
||||
Err(e) => {
|
||||
return Err(format!("failed to encode jxl '{}': {e}", path.display()));
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(e) = file.write(&jxl.data) {
|
||||
return Err(format!("failed to write jxl to '{}': {e}", path.display()));
|
||||
};
|
||||
}
|
||||
_ => {
|
||||
if let Err(e) = image.save(&path) {
|
||||
return Err(format!("failed to save '{}': {e}", path.display()));
|
||||
};
|
||||
}
|
||||
if let Err(e) = image.save(&path) {
|
||||
return Err(format!("failed to save '{}': {e}", path.display()));
|
||||
};
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
Loading…
Reference in a new issue