WIP thumbnails
This commit is contained in:
parent
24d71027f5
commit
21ec2db40f
22
Cargo.lock
generated
22
Cargo.lock
generated
@ -1591,6 +1591,16 @@ dependencies = [
|
|||||||
"wasi 0.14.2+wasi-0.2.4",
|
"wasi 0.14.2+wasi-0.2.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gexiv2-sys"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c4edf7a47be383873c52eb34426723c7c9b040f9e58cf5088f2253cef149daf1"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gif"
|
name = "gif"
|
||||||
version = "0.13.1"
|
version = "0.13.1"
|
||||||
@ -2106,6 +2116,7 @@ dependencies = [
|
|||||||
"memmap2",
|
"memmap2",
|
||||||
"minifb",
|
"minifb",
|
||||||
"pollster",
|
"pollster",
|
||||||
|
"rexiv2",
|
||||||
"threadpool",
|
"threadpool",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
@ -3792,6 +3803,17 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
|
checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rexiv2"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "11ecb9dccad43fea1bf58ea7bb8e34614446bea8aa00f78add6624d7ee26fb87"
|
||||||
|
dependencies = [
|
||||||
|
"gexiv2-sys",
|
||||||
|
"libc",
|
||||||
|
"num-rational",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rgb"
|
name = "rgb"
|
||||||
version = "0.8.50"
|
version = "0.8.50"
|
||||||
|
@ -13,6 +13,7 @@ itertools = "0.12"
|
|||||||
memmap2 = "0.9.5"
|
memmap2 = "0.9.5"
|
||||||
minifb = "0.28.0"
|
minifb = "0.28.0"
|
||||||
pollster = "0.4.0"
|
pollster = "0.4.0"
|
||||||
|
rexiv2 = "0.10.0"
|
||||||
threadpool = "1.8.1"
|
threadpool = "1.8.1"
|
||||||
# rustc-hash.workspace = true
|
# rustc-hash.workspace = true
|
||||||
tokio = { version = "1.44.1", features = ["sync"] }
|
tokio = { version = "1.44.1", features = ["sync"] }
|
||||||
@ -20,9 +21,6 @@ tracing-subscriber = "0.3"
|
|||||||
wgpu = "24.0.3"
|
wgpu = "24.0.3"
|
||||||
winit = "0.30.9"
|
winit = "0.30.9"
|
||||||
zune-image = {version = "0.4.15", features = ["all"]}
|
zune-image = {version = "0.4.15", features = ["all"]}
|
||||||
|
|
||||||
[profile.dev.package.zune-jpeg]
|
|
||||||
opt-level = 3
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
debug = false
|
debug = false
|
||||||
|
94
src/image.rs
94
src/image.rs
@ -1,13 +1,18 @@
|
|||||||
use iced::widget::image::Handle;
|
use iced::widget::image::Handle;
|
||||||
use iced::widget::image::Image as IcedImage;
|
use iced::widget::image::Image as IcedImage;
|
||||||
|
// use image::codecs::jpeg::JpegDecoder;
|
||||||
|
// use image::codecs::jpeg::JpegDecoder;
|
||||||
use image::DynamicImage;
|
use image::DynamicImage;
|
||||||
use image::ImageReader;
|
use image::ImageReader;
|
||||||
|
use itertools::Itertools;
|
||||||
use memmap2::Mmap;
|
use memmap2::Mmap;
|
||||||
|
use zune_image::codecs::jpeg::JpegDecoder;
|
||||||
use zune_image::codecs::qoi::zune_core::options::DecoderOptions;
|
use zune_image::codecs::qoi::zune_core::options::DecoderOptions;
|
||||||
use zune_image::image::Image as ZuneImage;
|
use zune_image::image::Image as ZuneImage;
|
||||||
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
use std::fs::read;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
@ -53,6 +58,12 @@ pub fn read_zune_image(mmap: &[u8]) -> Result<ZuneImage, String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_zune_image_path(path: &str) -> ZuneImage {
|
pub fn read_zune_image_path(path: &str) -> ZuneImage {
|
||||||
|
// let file = File::open(path).unwrap();
|
||||||
|
// let file_contents = read(path).unwrap();
|
||||||
|
// let mmap = map_file_path(path.into()).unwrap();
|
||||||
|
// let decoder = JpegDecoder::new(&file_contents);
|
||||||
|
// decoder.decode_into()
|
||||||
|
// ZuneImage::read(mmap, DecoderOptions::new_fast()).map_err(|e| e.to_string())
|
||||||
zune_image::image::Image::open_with_options(path, DecoderOptions::new_fast()).unwrap()
|
zune_image::image::Image::open_with_options(path, DecoderOptions::new_fast()).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,34 +148,53 @@ pub fn load_image_argb(path: PathBuf) -> ImflowImageBuffer {
|
|||||||
|
|
||||||
// Stage 1: Memory map the file
|
// Stage 1: Memory map the file
|
||||||
let stage1_start = Instant::now();
|
let stage1_start = Instant::now();
|
||||||
let mmap = map_file_path(path).unwrap();
|
let mmap = map_file_path(path.clone()).unwrap();
|
||||||
let stage1_time = stage1_start.elapsed();
|
let stage1_time = stage1_start.elapsed();
|
||||||
println!("File mapping took: {:?}", stage1_time);
|
// println!("File mapping took: {:?}", stage1_time);
|
||||||
|
|
||||||
|
// let file = File::open(path).unwrap();
|
||||||
|
let file_contents = read(path).unwrap();
|
||||||
|
// let mmap = map_file_path(path.into()).unwrap();
|
||||||
|
|
||||||
|
let mut decoder = JpegDecoder::new(&file_contents);
|
||||||
|
let options = DecoderOptions::new_fast()
|
||||||
|
.jpeg_set_max_scans(5)
|
||||||
|
.jpeg_set_out_colorspace(zune_image::codecs::qoi::zune_core::colorspace::ColorSpace::BGRA);
|
||||||
|
decoder.set_options(options);
|
||||||
|
decoder.decode_headers().unwrap();
|
||||||
|
let info = decoder.info().unwrap();
|
||||||
|
let width = info.width as usize;
|
||||||
|
let height = info.height as usize;
|
||||||
|
println!("{} x {}", width, height);
|
||||||
|
let mut buffer2: Vec<u8> = vec![0; width * height * 4];
|
||||||
|
decoder.decode_into(buffer2.as_mut_slice());
|
||||||
|
|
||||||
// Stage 2: Read the image
|
// Stage 2: Read the image
|
||||||
let stage2_start = Instant::now();
|
// let stage2_start = Instant::now();
|
||||||
let img = read_zune_image(mmap.deref()).unwrap();
|
// let img = read_zune_image(mmap.deref()).unwrap();
|
||||||
let width = img.dimensions().0;
|
// let width = img.dimensions().0;
|
||||||
let height = img.dimensions().1;
|
// let height = img.dimensions().1;
|
||||||
let stage2_time = stage2_start.elapsed();
|
// let stage2_time = stage2_start.elapsed();
|
||||||
println!("Image decoding took: {:?}", stage2_time);
|
// println!("Image decoding took: {:?}", stage2_time);
|
||||||
|
|
||||||
// Stage 3: Flatten the image
|
// Stage 3: Flatten the image
|
||||||
let stage3_start = Instant::now();
|
// let stage3_start = Instant::now();
|
||||||
let flat = &mut flatten_zune_image(&img)[0];
|
// let flat = &mut flatten_zune_image(&img)[0];
|
||||||
let stage3_time = stage3_start.elapsed();
|
// let stage3_time = stage3_start.elapsed();
|
||||||
println!("Image flattening took: {:?}", stage3_time);
|
// println!("Image flattening took: {:?}", stage3_time);
|
||||||
|
|
||||||
// Stage 4: Convert to ARGB format
|
// Stage 4: Convert to ARGB format
|
||||||
let stage4_start = Instant::now();
|
let stage4_start = Instant::now();
|
||||||
let mut buffer: Vec<u32> = vec![0; width * height];
|
// let mut buffer: Vec<u32> = vec![0; width * height];
|
||||||
|
|
||||||
for (rgba, argb) in flat.chunks_mut(3).zip(buffer.iter_mut()) {
|
// for (rgba, argb) in buffer2.chunks_mut(4).zip(buffer.iter_mut()) {
|
||||||
let r = rgba[0] as u32;
|
// let r = rgba[0] as u32;
|
||||||
let g = rgba[1] as u32;
|
// let g = rgba[1] as u32;
|
||||||
let b = rgba[2] as u32;
|
// let b = rgba[2] as u32;
|
||||||
*argb = r << 16 | g << 8 | b;
|
// *argb = r << 16 | g << 8 | b;
|
||||||
}
|
// }
|
||||||
|
let buffer: &[u32] =
|
||||||
|
unsafe { std::slice::from_raw_parts(buffer2.as_ptr() as *const u32, buffer2.len() / 4) };
|
||||||
let stage4_time = stage4_start.elapsed();
|
let stage4_time = stage4_start.elapsed();
|
||||||
println!("RGBA to ARGB conversion took: {:?}", stage4_time);
|
println!("RGBA to ARGB conversion took: {:?}", stage4_time);
|
||||||
|
|
||||||
@ -175,7 +205,7 @@ pub fn load_image_argb(path: PathBuf) -> ImflowImageBuffer {
|
|||||||
ImflowImageBuffer {
|
ImflowImageBuffer {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
argb_buffer: buffer,
|
argb_buffer: buffer.to_vec(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,21 +222,23 @@ pub fn load_image_argb_imagers(path: PathBuf) -> ImflowImageBuffer {
|
|||||||
let stage1_start = Instant::now();
|
let stage1_start = Instant::now();
|
||||||
let mmap = map_file_path(path).unwrap();
|
let mmap = map_file_path(path).unwrap();
|
||||||
let stage1_time = stage1_start.elapsed();
|
let stage1_time = stage1_start.elapsed();
|
||||||
println!("File mapping took: {:?}", stage1_time);
|
// println!("File mapping took: {:?}", stage1_time);
|
||||||
|
|
||||||
// Stage 2: Read the image
|
// Stage 2: Read the image
|
||||||
let stage2_start = Instant::now();
|
let stage2_start = Instant::now();
|
||||||
let img = image::load_from_memory(mmap.deref()).map_err(|e| e.to_string()).unwrap();
|
let img = image::load_from_memory(mmap.deref())
|
||||||
|
.map_err(|e| e.to_string())
|
||||||
|
.unwrap();
|
||||||
let width = img.width() as usize;
|
let width = img.width() as usize;
|
||||||
let height = img.height() as usize;
|
let height = img.height() as usize;
|
||||||
let stage2_time = stage2_start.elapsed();
|
let stage2_time = stage2_start.elapsed();
|
||||||
println!("Image decoding took: {:?}", stage2_time);
|
// println!("Image decoding took: {:?}", stage2_time);
|
||||||
|
|
||||||
// Stage 3: Flatten the image
|
// Stage 3: Flatten the image
|
||||||
let stage3_start = Instant::now();
|
let stage3_start = Instant::now();
|
||||||
let mut flat = img.into_rgba8().into_raw();
|
let mut flat = img.into_rgba8().into_raw();
|
||||||
let stage3_time = stage3_start.elapsed();
|
let stage3_time = stage3_start.elapsed();
|
||||||
println!("Image flattening took: {:?}", stage3_time);
|
// println!("Image flattening took: {:?}", stage3_time);
|
||||||
|
|
||||||
// Stage 4: Convert to ARGB format
|
// Stage 4: Convert to ARGB format
|
||||||
let stage4_start = Instant::now();
|
let stage4_start = Instant::now();
|
||||||
@ -219,7 +251,7 @@ pub fn load_image_argb_imagers(path: PathBuf) -> ImflowImageBuffer {
|
|||||||
*argb = r << 16 | g << 8 | b;
|
*argb = r << 16 | g << 8 | b;
|
||||||
}
|
}
|
||||||
let stage4_time = stage4_start.elapsed();
|
let stage4_time = stage4_start.elapsed();
|
||||||
println!("RGBA to ARGB conversion took: {:?}", stage4_time);
|
// println!("RGBA to ARGB conversion took: {:?}", stage4_time);
|
||||||
|
|
||||||
// Total time
|
// Total time
|
||||||
let total_time = total_start.elapsed();
|
let total_time = total_start.elapsed();
|
||||||
@ -240,3 +272,15 @@ pub fn load_available_images(dir: PathBuf) -> Vec<PathBuf> {
|
|||||||
files
|
files
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_embedded_thumbnail(path: PathBuf) -> Option<Vec<u8>> {
|
||||||
|
let meta = rexiv2::Metadata::new_from_path(path);
|
||||||
|
match meta {
|
||||||
|
Ok(meta) => {
|
||||||
|
meta.get_thumbnail().map(|v| v.to_vec())
|
||||||
|
}
|
||||||
|
Err(e) => None,
|
||||||
|
}
|
||||||
|
// let file = std::fs::File::open(path).ok()?;
|
||||||
|
// let exif = Reader::new().read_from_container(&mut std::io::BufReader::new(file)).ok()?;
|
||||||
|
// exif.get_thumbnail()
|
||||||
|
}
|
||||||
|
124
src/main.rs
124
src/main.rs
@ -5,7 +5,7 @@
|
|||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::fs::{self};
|
use std::fs::{self};
|
||||||
use std::io::Read;
|
use std::io::{Cursor, Read};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::time::{self, Duration, Instant};
|
use std::time::{self, Duration, Instant};
|
||||||
@ -20,15 +20,15 @@ use iced::widget::{
|
|||||||
use iced::{Center, Element, Fill, Length, Size, Subscription, Task, Theme, keyboard};
|
use iced::{Center, Element, Fill, Length, Size, Subscription, Task, Theme, keyboard};
|
||||||
use image::{self, DynamicImage, EncodableLayout, GenericImageView, ImageBuffer, ImageReader};
|
use image::{self, DynamicImage, EncodableLayout, GenericImageView, ImageBuffer, ImageReader};
|
||||||
|
|
||||||
|
use clap::Parser;
|
||||||
use imflow::image::{
|
use imflow::image::{
|
||||||
Approach, ImflowImageBuffer, flatten_image_image, flatten_zune_image, load_available_images,
|
Approach, ImflowImageBuffer, flatten_image_image, flatten_zune_image, get_embedded_thumbnail,
|
||||||
load_image_argb, load_image_argb_imagers, load_thumbnail, map_file, map_file_path,
|
load_available_images, load_image_argb, load_image_argb_imagers, load_thumbnail, map_file,
|
||||||
read_zune_image,
|
map_file_path, read_zune_image,
|
||||||
};
|
};
|
||||||
use minifb::{Key, Window, WindowOptions};
|
use minifb::{Key, Window, WindowOptions};
|
||||||
use threadpool::ThreadPool;
|
use threadpool::ThreadPool;
|
||||||
use zune_image::codecs::qoi::zune_core::options::DecoderOptions; // for general image operations
|
use zune_image::codecs::qoi::zune_core::options::DecoderOptions; // for general image operations
|
||||||
use clap::Parser;
|
|
||||||
// use image::io::Reader as ImageReader; // specifically for Reader
|
// use image::io::Reader as ImageReader; // specifically for Reader
|
||||||
|
|
||||||
use std::sync::{Arc, mpsc};
|
use std::sync::{Arc, mpsc};
|
||||||
@ -336,22 +336,25 @@ use std::sync::{Arc, mpsc};
|
|||||||
struct State {
|
struct State {
|
||||||
current_image_id: usize,
|
current_image_id: usize,
|
||||||
loaded_images: HashMap<PathBuf, ImflowImageBuffer>,
|
loaded_images: HashMap<PathBuf, ImflowImageBuffer>,
|
||||||
|
loaded_images_thumbnails: HashMap<PathBuf, ImflowImageBuffer>,
|
||||||
available_images: Vec<PathBuf>,
|
available_images: Vec<PathBuf>,
|
||||||
current_image_path: PathBuf,
|
current_image_path: PathBuf,
|
||||||
pool: ThreadPool,
|
pool: ThreadPool,
|
||||||
loader_rx: mpsc::Receiver<(PathBuf, ImflowImageBuffer)>,
|
loader_rx: mpsc::Receiver<(PathBuf, ImflowImageBuffer)>,
|
||||||
loader_tx: mpsc::Sender<(PathBuf, ImflowImageBuffer)>,
|
loader_tx: mpsc::Sender<(PathBuf, ImflowImageBuffer)>,
|
||||||
currently_loading: HashSet<PathBuf>, // Track what's being loaded
|
currently_loading: HashSet<PathBuf>, // Track what's being loaded
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
fn new(path: PathBuf) -> Self {
|
fn new(path: PathBuf) -> Self {
|
||||||
let current_image_id: usize = 0;
|
let current_image_id: usize = 0;
|
||||||
let mut loaded_images: HashMap<PathBuf, ImflowImageBuffer> = HashMap::new();
|
let mut loaded_images: HashMap<PathBuf, ImflowImageBuffer> = HashMap::new();
|
||||||
|
let mut loaded_thumbnails: HashMap<PathBuf, ImflowImageBuffer> = HashMap::new();
|
||||||
let available_images = load_available_images(path);
|
let available_images = load_available_images(path);
|
||||||
let new_path = available_images[0].clone();
|
let new_path = available_images[0].clone();
|
||||||
let current_image = load_image_argb_imagers(new_path.clone());
|
// let current_image = load_image_argb_imagers(new_path.clone());
|
||||||
loaded_images.insert(new_path.clone(), current_image);
|
// let current_image = load_image_argb_imagers(new_path.clone());
|
||||||
|
// loaded_images.insert(new_path.clone(), current_image);
|
||||||
|
|
||||||
let (loader_tx, loader_rx) = mpsc::channel();
|
let (loader_tx, loader_rx) = mpsc::channel();
|
||||||
|
|
||||||
@ -359,6 +362,35 @@ impl State {
|
|||||||
|
|
||||||
let currently_loading = HashSet::new();
|
let currently_loading = HashSet::new();
|
||||||
|
|
||||||
|
for path in &available_images {
|
||||||
|
if let Some(thumbnail) = get_embedded_thumbnail(path.clone()) {
|
||||||
|
let decoder = image::ImageReader::new(Cursor::new(thumbnail))
|
||||||
|
.with_guessed_format()
|
||||||
|
.unwrap();
|
||||||
|
let image = decoder.decode().unwrap();
|
||||||
|
|
||||||
|
let width: usize = image.width() as usize;
|
||||||
|
let height: usize = image.height() as usize;
|
||||||
|
let mut flat = image.into_rgba8().into_raw();
|
||||||
|
let mut buffer: Vec<u32> = vec![0; width * height];
|
||||||
|
|
||||||
|
for (rgba, argb) in flat.chunks_mut(4).zip(buffer.iter_mut()) {
|
||||||
|
let r = rgba[0] as u32;
|
||||||
|
let g = rgba[1] as u32;
|
||||||
|
let b = rgba[2] as u32;
|
||||||
|
*argb = r << 16 | g << 8 | b;
|
||||||
|
}
|
||||||
|
|
||||||
|
let buf = ImflowImageBuffer {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
argb_buffer: buffer,
|
||||||
|
};
|
||||||
|
|
||||||
|
loaded_thumbnails.insert(path.clone(), buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut state = Self {
|
let mut state = Self {
|
||||||
current_image_id,
|
current_image_id,
|
||||||
loaded_images,
|
loaded_images,
|
||||||
@ -367,10 +399,13 @@ impl State {
|
|||||||
pool,
|
pool,
|
||||||
loader_rx,
|
loader_rx,
|
||||||
loader_tx,
|
loader_tx,
|
||||||
currently_loading
|
currently_loading,
|
||||||
|
loaded_images_thumbnails: loaded_thumbnails,
|
||||||
};
|
};
|
||||||
|
|
||||||
state.preload_next_images(min(state.available_images.len(), 64));
|
// state.preload_next_images(min(state.available_images.len(), 1));
|
||||||
|
|
||||||
|
// let thumbnail_path = state.available_images[0].clone();
|
||||||
|
|
||||||
state
|
state
|
||||||
}
|
}
|
||||||
@ -390,6 +425,7 @@ impl State {
|
|||||||
|
|
||||||
self.pool.execute(move || {
|
self.pool.execute(move || {
|
||||||
let image = load_image_argb(path.clone());
|
let image = load_image_argb(path.clone());
|
||||||
|
// let image = load_image_argb_imagers(path.clone());
|
||||||
let _ = tx.send((path, image));
|
let _ = tx.send((path, image));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -407,7 +443,7 @@ impl State {
|
|||||||
as usize;
|
as usize;
|
||||||
let new_path = self.available_images[self.current_image_id].clone();
|
let new_path = self.available_images[self.current_image_id].clone();
|
||||||
if !self.loaded_images.contains_key(&new_path) {
|
if !self.loaded_images.contains_key(&new_path) {
|
||||||
self.request_load(new_path.clone());
|
// self.request_load(new_path.clone());
|
||||||
}
|
}
|
||||||
self.current_image_path = new_path;
|
self.current_image_path = new_path;
|
||||||
}
|
}
|
||||||
@ -415,6 +451,41 @@ impl State {
|
|||||||
fn get_current_image(&self) -> Option<&ImflowImageBuffer> {
|
fn get_current_image(&self) -> Option<&ImflowImageBuffer> {
|
||||||
self.loaded_images.get(&self.current_image_path)
|
self.loaded_images.get(&self.current_image_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_thumbnail(&mut self) -> &ImflowImageBuffer {
|
||||||
|
if self.loaded_images_thumbnails.contains_key(&self.current_image_path) {
|
||||||
|
return self.loaded_images_thumbnails.get(&self.current_image_path).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = &self.current_image_path;
|
||||||
|
if let Some(thumbnail) = get_embedded_thumbnail(path.clone()) {
|
||||||
|
let decoder = image::ImageReader::new(Cursor::new(thumbnail))
|
||||||
|
.with_guessed_format()
|
||||||
|
.unwrap();
|
||||||
|
let image = decoder.decode().unwrap();
|
||||||
|
|
||||||
|
let width: usize = image.width() as usize;
|
||||||
|
let height: usize = image.height() as usize;
|
||||||
|
let mut flat = image.into_rgba8().into_raw();
|
||||||
|
let mut buffer: Vec<u32> = vec![0; width * height];
|
||||||
|
|
||||||
|
for (rgba, argb) in flat.chunks_mut(4).zip(buffer.iter_mut()) {
|
||||||
|
let r = rgba[0] as u32;
|
||||||
|
let g = rgba[1] as u32;
|
||||||
|
let b = rgba[2] as u32;
|
||||||
|
*argb = r << 16 | g << 8 | b;
|
||||||
|
}
|
||||||
|
|
||||||
|
let buf = ImflowImageBuffer {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
argb_buffer: buffer,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.loaded_images_thumbnails.insert(path.clone(), buf);
|
||||||
|
}
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
@ -425,8 +496,8 @@ struct Args {
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
const WIDTH: usize = 1920;
|
const WIDTH: usize = 2000;
|
||||||
const HEIGHT: usize = 1080;
|
const HEIGHT: usize = 1000;
|
||||||
let mut window = Window::new(
|
let mut window = Window::new(
|
||||||
"Test - ESC to exit",
|
"Test - ESC to exit",
|
||||||
WIDTH,
|
WIDTH,
|
||||||
@ -441,27 +512,32 @@ fn main() {
|
|||||||
|
|
||||||
let path = args.path.unwrap_or("./test_images".into());
|
let path = args.path.unwrap_or("./test_images".into());
|
||||||
let mut state = State::new(path);
|
let mut state = State::new(path);
|
||||||
let mut waiting = true;
|
let mut waiting = false;
|
||||||
window.set_key_repeat_delay(0.1);
|
window.set_key_repeat_delay(0.1);
|
||||||
window.set_key_repeat_rate(0.1);
|
window.set_key_repeat_rate(0.1);
|
||||||
|
|
||||||
|
let thumbs: Vec<&ImflowImageBuffer> = state.loaded_images_thumbnails.values().collect();
|
||||||
|
show_image(&mut window, thumbs[0]);
|
||||||
|
|
||||||
while window.is_open() && !window.is_key_down(Key::Escape) {
|
while window.is_open() && !window.is_key_down(Key::Escape) {
|
||||||
window.update();
|
window.update();
|
||||||
state.check_loaded_images();
|
state.check_loaded_images();
|
||||||
if window.is_key_pressed(Key::Right, minifb::KeyRepeat::Yes) {
|
if !waiting && window.is_key_pressed(Key::Right, minifb::KeyRepeat::Yes) {
|
||||||
state.next_image(1);
|
state.next_image(1);
|
||||||
waiting = true;
|
show_image(&mut window, state.get_thumbnail());
|
||||||
} else if window.is_key_pressed(Key::Left, minifb::KeyRepeat::Yes) {
|
// waiting = true;
|
||||||
|
} else if !waiting && window.is_key_pressed(Key::Left, minifb::KeyRepeat::Yes) {
|
||||||
state.next_image(-1);
|
state.next_image(-1);
|
||||||
waiting = true;
|
show_image(&mut window, state.get_thumbnail());
|
||||||
|
// waiting = true;
|
||||||
}
|
}
|
||||||
if waiting {
|
// if waiting {
|
||||||
if let Some(image) = state.get_current_image(){
|
// if let Some(image) = state.get_current_image() {
|
||||||
waiting = false;
|
// waiting = false;
|
||||||
|
|
||||||
show_image(&mut window, &image);
|
// show_image(&mut window, &image);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user