feat: proof of concept

This commit is contained in:
electria 2026-08-04 08:31:02 -07:00
commit 25b5c413c1
Signed by: electria
SSH key fingerprint: SHA256:8LlB3ucPbBHqozqkhsNbaV5oG3SlzzqUj8FZDL6IPQs
4 changed files with 154 additions and 15 deletions

93
Cargo.lock generated
View file

@ -48,6 +48,15 @@ dependencies = [
"zerocopy",
]
[[package]]
name = "aho-corasick"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba"
dependencies = [
"memchr",
]
[[package]]
name = "aligned"
version = "0.4.3"
@ -490,6 +499,16 @@ dependencies = [
"alloc-stdlib",
]
[[package]]
name = "bstr"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f7dc094d718f2e1c1559ad110e27eeaae14a5465d3d56dd6dbd793079fbd530"
dependencies = [
"memchr",
"serde_core",
]
[[package]]
name = "built"
version = "0.8.1"
@ -1398,6 +1417,21 @@ dependencies = [
"slab",
]
[[package]]
name = "gallery"
version = "0.1.0"
dependencies = [
"iced",
"ignore",
"image",
"jxl-oxide",
"kra-image-integration",
"rayon",
"rfd",
"size",
"zip",
]
[[package]]
name = "gethostname"
version = "1.1.0"
@ -1460,6 +1494,19 @@ version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "151665d9be52f9bb40fc7966565d39666f2d1e69233571b71b87791c7e0528b3"
[[package]]
name = "globset"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07c34a9410465b45bd9787443bc7370f37735bad04b0f0cd57ff1a3186c98988"
dependencies = [
"aho-corasick",
"bstr",
"log",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "glow"
version = "0.16.0"
@ -1659,19 +1706,6 @@ dependencies = [
"thiserror 2.0.19",
]
[[package]]
name = "iced-template"
version = "0.1.0"
dependencies = [
"iced",
"image",
"jxl-oxide",
"kra-image-integration",
"rfd",
"size",
"zip",
]
[[package]]
name = "iced_core"
version = "0.14.0"
@ -1842,6 +1876,22 @@ dependencies = [
"winit",
]
[[package]]
name = "ignore"
version = "0.4.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b69833ed729dc5aa7d19541d96d6cf8e9137194207a04916d658e43168402f"
dependencies = [
"crossbeam-deque",
"globset",
"log",
"memchr",
"regex-automata",
"same-file",
"walkdir",
"winapi-util",
]
[[package]]
name = "image"
version = "0.25.10"
@ -3536,6 +3586,23 @@ dependencies = [
"bitflags 2.13.1",
]
[[package]]
name = "regex-automata"
version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
[[package]]
name = "renderdoc-sys"
version = "1.1.0"

View file

@ -5,7 +5,9 @@ edition = "2024"
license = "AGPL-3.0-or-later"
[dependencies]
ignore = "0.4.33"
kra-image-integration = "0.1.0"
rayon = "1.12.0"
rfd = "0.17.2"
size = "0.5.0"
zip = "8.6.0"

View file

@ -1,26 +1,88 @@
use std::{
borrow::Cow,
collections::HashMap,
env,
path::{Path, PathBuf},
};
use iced::{Color, Element, Renderer, Task, Theme, application, theme, widget};
use ignore::{WalkBuilder, types::TypesBuilder};
use image::{DynamicImage, EncodableLayout, RgbaImage};
use rayon::iter::{ParallelBridge, ParallelIterator};
use crate::SUPPORTED_TYPES;
enum Message {}
#[derive(Default)]
enum Mode {
Focused(usize),
Focused(PathBuf),
#[default]
Gallery,
}
#[derive(Default)]
struct State {
mode: Mode,
images: HashMap<PathBuf, Option<(RgbaImage, widget::image::Handle)>>,
}
impl State {
fn new() -> Self {
let mut builder = TypesBuilder::new();
builder.add_defaults();
for ext in SUPPORTED_TYPES {
builder.add("supportedImages", ext).unwrap();
}
builder.select("supportedImages");
Self {
mode: Mode::Gallery,
images: WalkBuilder::new(
env::args()
.nth(1)
.map(Cow::Owned)
.unwrap_or(Cow::Borrowed("./"))
.as_ref(),
)
.types(builder.build().unwrap())
.max_depth(Some(1))
.build()
.par_bridge()
.filter_map(|r| {
r.inspect_err(|e| eprintln!("{e}"))
.ok()
.map(|entry| entry.into_path())
})
.filter(|path| path.is_file())
.map(|path| {
let image = image::open(&path)
.inspect_err(|e| eprintln!("{e}"))
.ok()
.map(DynamicImage::into_rgba8);
let handle = image.as_ref().map(|image| {
widget::image::Handle::from_rgba(image.width(), image.height(), unsafe {
std::mem::transmute::<&[u8], &'static [u8]>(image.as_bytes())
})
});
(path, image.map(|image| (image, handle.unwrap())))
})
.collect(),
}
}
fn update(&mut self, message: Message) -> Task<Message> {
Task::none()
}
fn view(&self) -> Element<'_, Message, Theme, Renderer> {
widget::text("hiiiiiii").into()
widget::scrollable(widget::column(
self.images
.iter()
.filter_map(|(_k, v)| v.as_ref())
.map(|(_image, handle)| {
dbg!();
widget::image(handle).into()
}),
))
.into()
}
}

View file

@ -1,5 +1,13 @@
mod app;
const SUPPORTED_TYPES: &[&str; 20] = &[
"*.png", "*.PNG", "*.jpg", "*.JPG", "*.jpeg", "*.JPEG", "*.avif", "*.jxl", "*.bmp", "*.exr",
"*.ff", "*.gif", "*.hdr", "*.ico", "*.pnm", "*.qoi", "*.tga", "*.tiff", "*.webp", "*.kra",
];
fn main() -> Result<(), impl std::error::Error> {
jxl_oxide::integration::register_image_decoding_hook();
kra_image_integration::register();
app::run()
}