feat: kra (krita) support

This commit is contained in:
electria 2026-07-30 22:41:17 -07:00
commit fc92ff60e0
Signed by: electria
SSH key fingerprint: SHA256:8LlB3ucPbBHqozqkhsNbaV5oG3SlzzqUj8FZDL6IPQs
3 changed files with 430 additions and 33 deletions

View file

@ -1,50 +1,123 @@
use std::path::{Path, PathBuf};
use std::{
fs,
io::{self, Read},
path::{Path, PathBuf},
};
use iced::widget;
use image::{DynamicImage, ImageDecoder, ImageReader, RgbaImage};
use rfd::FileDialog;
use zip::ZipArchive;
pub fn load_image(path: impl AsRef<Path>) -> Result<RgbaImage, String> {
let path = path.as_ref();
let reader = match ImageReader::open(path) {
Ok(r) => r,
Err(e) => {
let decoded_image = if path.extension().is_some_and(|ext| ext == "kra") {
let reader = match fs::File::open(path).map(io::BufReader::new) {
Ok(r) => r,
Err(e) => {
return Err(format!(
"failed to create reader for '{}': {e}",
path.display()
));
}
};
let mut zip = match ZipArchive::new(reader) {
Ok(z) => z,
Err(e) => {
return Err(format!(
"failed to open zip archive '{}': {e}",
path.display()
));
}
};
let mut reader = match zip.by_name("mergedimage.png") {
Ok(r) => r,
Err(e) => {
return Err(format!(
"failed to open file in zip archive '{}': {e}",
path.display()
));
}
};
// reading it all and wrapping it with a Cursor
// is the only way I know to give it Seek
// (which is required by ImageReader)
let mut buf = Vec::new();
if let Err(e) = reader.read_to_end(&mut buf) {
return Err(format!(
"failed to create reader for '{}': {e}",
"error when reading file in zip archive '{}': {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 image_reader = ImageReader::with_format(io::Cursor::new(buf), image::ImageFormat::Png);
let oreintation = match decoder.orientation() {
Ok(o) => o,
Err(e) => {
return Err(format!(
"failed to get oreintation of '{}': {e}",
path.display()
));
}
};
let decoder = match image_reader.into_decoder() {
Ok(d) => d,
Err(e) => {
return Err(format!(
"failed to create decoder for '{}': {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()));
}
};
let 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
} else {
let image_reader = match ImageReader::open(path) {
Ok(r) => r,
Err(e) => {
return Err(format!(
"failed to create image reader for '{}': {e}",
path.display()
));
}
};
let mut decoder = match image_reader.into_decoder() {
Ok(d) => d,
Err(e) => {
return Err(format!(
"failed to create decoder for '{}': {e}",
path.display()
));
}
};
// we don't need to check this for the kra branch
// since PNGs don't have metadata oreintation
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
};
Ok(decoded_image.into_rgba8())
}
@ -54,7 +127,7 @@ pub fn pick_image() -> Result<PathBuf, String> {
"image",
&[
"png", "PNG", "jpg", "JPG", "jpeg", "JPEG", "avif", "jxl", "bmp", "exr", "ff",
"gif", "hdr", "ico", "pnm", "qoi", "tga", "tiff", "webp",
"gif", "hdr", "ico", "pnm", "qoi", "tga", "tiff", "webp", "kra",
],
)
.pick_file()